summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-06-11 14:21:06 -0400
committerRuss Cox <rsc@golang.org>2014-06-11 14:21:06 -0400
commit80a3f744d6f93f4d120fab06af963dab8ce9d8e0 (patch)
treeb72d19956386aa4ede98a4fa49949ddf200c2343
parentc80394890fc23e1bb14e69be7c34623984772f73 (diff)
downloadgo-80a3f744d6f93f4d120fab06af963dab8ce9d8e0.tar.gz
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 issue 8185. LGTM=iant R=iant CC=golang-codereviews https://codereview.appspot.com/108870044
-rw-r--r--src/cmd/gc/esc.c13
-rw-r--r--test/escape2.go12
2 files changed, 23 insertions, 2 deletions
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index 9d7dc1149..78624d7cb 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -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;
}
}
diff --git a/test/escape2.go b/test/escape2.go
index f00741dc2..28251aa98 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -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
+}