mirror of
https://github.com/golang/go
synced 2024-09-06 00:19:45 +00:00
cmd/gc: fix &result escaping into result
There is a hierarchy of location defined by loop depth: -1 = the heap 0 = function results 1 = local variables (and parameters) 2 = local variable declared inside a loop 3 = local variable declared inside a loop inside a loop etc In general if an address from loopdepth n is assigned to something in loop depth m < n, that indicates an extended lifetime of some form that requires a heap allocation. Function results can be local variables too, though, and so they don't actually fit into the hierarchy very well. Treat the address of a function result as level 1 so that if it is written back into a result, the address is treated as escaping. Fixes #8185. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/108870044
This commit is contained in:
parent
be91bc29a4
commit
f20e4d5ecb
|
@ -673,12 +673,21 @@ esc(EscState *e, Node *n, Node *up)
|
|||
// for &x, use loop depth of x if known.
|
||||
// it should always be known, but if not, be conservative
|
||||
// and keep the current loop depth.
|
||||
if(n->left->op == ONAME && (n->left->escloopdepth != 0 || n->left->class == PPARAMOUT)) {
|
||||
if(n->left->op == ONAME) {
|
||||
switch(n->left->class) {
|
||||
case PAUTO:
|
||||
if(n->left->escloopdepth != 0)
|
||||
n->escloopdepth = n->left->escloopdepth;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
n->escloopdepth = n->left->escloopdepth;
|
||||
// PPARAM is loop depth 1 always.
|
||||
// PPARAMOUT is loop depth 0 for writes
|
||||
// but considered loop depth 1 for address-of,
|
||||
// so that writing the address of one result
|
||||
// to another (or the same) result makes the
|
||||
// first result move to the heap.
|
||||
n->escloopdepth = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1478,3 +1478,15 @@ func foo153(v interface{}) *int { // ERROR "leaking param: v"
|
|||
}
|
||||
panic(0)
|
||||
}
|
||||
|
||||
// issue 8185 - &result escaping into result
|
||||
|
||||
func f() (x int, y *int) { // ERROR "moved to heap: x"
|
||||
y = &x // ERROR "&x escapes to heap"
|
||||
return
|
||||
}
|
||||
|
||||
func g() (x interface{}) { // ERROR "moved to heap: x"
|
||||
x = &x // ERROR "&x escapes to heap"
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue