mirror of
https://github.com/golang/go
synced 2024-11-13 14:20:23 -07:00
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
This commit is contained in:
parent
0627fa84b7
commit
948b2c722b
@ -1490,6 +1490,7 @@ sgen(Node *n, Node *res, int64 w)
|
|||||||
}
|
}
|
||||||
if(osrc%align != 0 || odst%align != 0)
|
if(osrc%align != 0 || odst%align != 0)
|
||||||
fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
|
fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
|
||||||
|
|
||||||
// if we are copying forward on the stack and
|
// if we are copying forward on the stack and
|
||||||
// the src and dst overlap, then reverse direction
|
// the src and dst overlap, then reverse direction
|
||||||
dir = align;
|
dir = align;
|
||||||
@ -1674,6 +1675,13 @@ componentgen(Node *nr, Node *nl)
|
|||||||
freer = 1;
|
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) {
|
switch(nl->type->etype) {
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
if(nl->op == ONAME)
|
if(nl->op == ONAME)
|
||||||
|
@ -1585,6 +1585,13 @@ componentgen(Node *nr, Node *nl)
|
|||||||
freer = 1;
|
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) {
|
switch(nl->type->etype) {
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
|
@ -462,6 +462,7 @@ Node*
|
|||||||
nodarg(Type *t, int fp)
|
nodarg(Type *t, int fp)
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
|
NodeList *l;
|
||||||
Type *first;
|
Type *first;
|
||||||
Iter savet;
|
Iter savet;
|
||||||
|
|
||||||
@ -482,6 +483,14 @@ nodarg(Type *t, int fp)
|
|||||||
|
|
||||||
if(t->etype != TFIELD)
|
if(t->etype != TFIELD)
|
||||||
fatal("nodarg: not field %T", t);
|
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 = nod(ONAME, N, N);
|
||||||
n->type = t->type;
|
n->type = t->type;
|
||||||
|
@ -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) {
|
switch(nl->type->etype) {
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
if(nl->op == ONAME)
|
if(nl->op == ONAME)
|
||||||
|
@ -1652,7 +1652,8 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
|
|||||||
// optimization - can do block copy
|
// optimization - can do block copy
|
||||||
if(eqtypenoname(r->type, *nl)) {
|
if(eqtypenoname(r->type, *nl)) {
|
||||||
a = nodarg(*nl, fp);
|
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));
|
nn = list1(convas(nod(OAS, a, r), init));
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
26
test/live.go
26
test/live.go
@ -564,3 +564,29 @@ func f38(b bool) {
|
|||||||
}
|
}
|
||||||
println()
|
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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user