Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/gc: inlining leaves pointer references in stack temporaries #4217

Closed
bradfitz opened this issue Oct 9, 2012 · 8 comments
Closed

cmd/gc: inlining leaves pointer references in stack temporaries #4217

bradfitz opened this issue Oct 9, 2012 · 8 comments
Milestone

Comments

@bradfitz
Copy link
Contributor

bradfitz commented Oct 9, 2012

The attached program generates garbage.

It does not generate garbage if I compile with -l:

Compare:

$ go run -gcflags -l leak.go
vs.
$ go run leak.go

Attachments:

  1. leak.go (998 bytes)
@rsc
Copy link
Contributor

rsc commented Oct 9, 2012

Comment 1:

This looks like a dup of issue #353. Calling foo(b) stores b in a temporary variable that
won't be cleared until the function returns, and it until it does, the reference is
findable on the stack. Inlining definitly exacerbates this, because without inlining
there wouldn't be a separate slot for the copy of the variable, so calling the channel
runtime would smash the pointers on the stack from the call to foo. The only sure-fire
way to drop the references to pointers on the stack is to let the goroutine exit.
I'll try to think of some way to help this case.

@bradfitz
Copy link
Contributor Author

bradfitz commented Oct 9, 2012

Comment 2:

I've confirmed that changing the foo(b) function to not be inlinable fixes the leak:
func foo(b buffer) {
        bar()
}
var x int
func bar() {
        x++
}

@rsc
Copy link
Contributor

rsc commented Oct 9, 2012

Comment 3:

Yes, the inlining matters because it effectively turns foo(b) into {tmp := b; /* body of
foo */} and then that temporary variable is still on the goroutine's main stack frame
for the rest of the loop. Only another call to foo would clear it.

@bradfitz
Copy link
Contributor Author

bradfitz commented Oct 9, 2012

Comment 4:

Yeah, I followed that part.  I was just making sure it could be worked around in code if
needed.  Unfortunately the real program in question is a bit more gnarly and I'm not
even sure which call is making the temporary, if my problem is even this bug.
How much work would it be to turn foo(b) into { tmp := b; /* body of foo */; tmp =
buffer{} } ?

@bradfitz
Copy link
Contributor Author

bradfitz commented Oct 9, 2012

Comment 5:

Came to reply to an email and got distracted and went exploring in gc.  As expected,
there are lots of data structures and conventions to learn.
In any case, the attached doesn't work, but you get the point.  I think the Nodes I
actually need to OAS[2] to N are in tinlvar(t) that are assigned in the OAS2 block
above, and probably after inlsubstlist but before the OGOTO?
</exploring>

@bradfitz
Copy link
Contributor Author

bradfitz commented Oct 9, 2012

Comment 6:

Er, didn't attach.

Attachments:

  1. x.patch (1595 bytes)

@lvdlvd
Copy link

lvdlvd commented Oct 17, 2012

Comment 7:

If i understand correctly, this also happens for any code that is explicitly written to
keep a pointer in a temporary, and a more fundamental fix would be to zero out any
pointers on the stack as they leave scope.  
escape analysis computes a 'loopdepth' for every variable, which comes close.  we could
insert a zeroing OAS for pointer typed variables at the end of their loops, that would
benefit everyone.
but if the problem is only bad for inlining, i can probably make x.patch work, i'll look
closer this afternoon.

@rsc
Copy link
Contributor

rsc commented Oct 17, 2012

Comment 8:

This is in fact a dup of 353.

Status changed to Duplicate.

Merged into issue #353.

@rsc rsc added this to the Go1.1 milestone Apr 14, 2015
@rsc rsc removed the go1.1 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
@rsc rsc removed their assignment Jun 22, 2022
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants