diff options
author | Russ Cox <rsc@golang.org> | 2014-05-28 19:50:19 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-05-28 19:50:19 -0400 |
commit | 948b2c722b32d2bc63d6f326c80831801b0e06f7 (patch) | |
tree | 14e168d564383337f52fbc0ba94e9b98ac11b005 | |
parent | 0627fa84b773fbb38b28727d99e7e35e7345ca05 (diff) | |
download | go-948b2c722b32d2bc63d6f326c80831801b0e06f7.tar.gz go-948b2c722b32d2bc63d6f326c80831801b0e06f7.zip |
cmd/gc: fix x=x crash
The 'nodarg' function is used to obtain a Node*
representing a function argument or result.
It returned a brand new Node*, but that violates
the guarantee in most places in the compiler that
two Node*s refer to the same variable if and only if
they are the same Node* pointer. Reestablish that
invariant by making nodarg return a preexisting
named variable if present.
Having fixed that, avoid any copy during x=x in
componentgen, because the VARDEF we emit
before the copy marks the lhs x as dead incorrectly.
The change in walk.c avoids modifying the result
of nodarg. This was the only place in the compiler
that did so.
Fixes #8097.
LGTM=r, khr
R=golang-codereviews, r, khr
CC=golang-codereviews, iant
https://golang.org/cl/102820043
-rw-r--r-- | src/cmd/5g/cgen.c | 8 | ||||
-rw-r--r-- | src/cmd/6g/cgen.c | 7 | ||||
-rw-r--r-- | src/cmd/6g/gsubr.c | 9 | ||||
-rw-r--r-- | src/cmd/8g/cgen.c | 7 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 3 | ||||
-rw-r--r-- | test/live.go | 26 |
6 files changed, 59 insertions, 1 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 9faf754617..9011b20228 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -1490,6 +1490,7 @@ sgen(Node *n, Node *res, int64 w) } if(osrc%align != 0 || odst%align != 0) fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); + // if we are copying forward on the stack and // the src and dst overlap, then reverse direction dir = align; @@ -1674,6 +1675,13 @@ componentgen(Node *nr, Node *nl) freer = 1; } + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; + switch(nl->type->etype) { case TARRAY: if(nl->op == ONAME) diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index ae1309142c..4dd505b086 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -1585,6 +1585,13 @@ componentgen(Node *nr, Node *nl) freer = 1; } } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; switch(nl->type->etype) { case TARRAY: diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index bd2f2304b4..e4d00bf419 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -462,6 +462,7 @@ Node* nodarg(Type *t, int fp) { Node *n; + NodeList *l; Type *first; Iter savet; @@ -482,6 +483,14 @@ nodarg(Type *t, int fp) if(t->etype != TFIELD) fatal("nodarg: not field %T", t); + + if(fp == 1) { + for(l=curfn->dcl; l; l=l->next) { + n = l->n; + if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym) + return n; + } + } n = nod(ONAME, N, N); n->type = t->type; diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index 1aae7771c7..d626c2eb02 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -1397,6 +1397,13 @@ componentgen(Node *nr, Node *nl) } } + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) + goto yes; + switch(nl->type->etype) { case TARRAY: if(nl->op == ONAME) diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 2d402d04f5..1cb25512e5 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1652,7 +1652,8 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL // optimization - can do block copy if(eqtypenoname(r->type, *nl)) { a = nodarg(*nl, fp); - a->type = r->type; + r = nod(OCONVNOP, r, N); + r->type = a->type; nn = list1(convas(nod(OAS, a, r), init)); goto ret; } diff --git a/test/live.go b/test/live.go index 21d3e6a5fa..286fcc3064 100644 --- a/test/live.go +++ b/test/live.go @@ -564,3 +564,29 @@ func f38(b bool) { } println() } + +// issue 8097: mishandling of x = x during return. + +func f39() (x []int) { + x = []int{1} + println() // ERROR "live at call to printnl: x" + return x +} + +func f39a() (x []int) { + x = []int{1} + println() // ERROR "live at call to printnl: x" + return +} + +func f39b() (x [10]*int) { + x = [10]*int{new(int)} // ERROR "live at call to new: x" + println() // ERROR "live at call to printnl: x" + return x +} + +func f39c() (x [10]*int) { + x = [10]*int{new(int)} // ERROR "live at call to new: x" + println() // ERROR "live at call to printnl: x" + return +} |