Commit 0227c45e authored by Russ Cox's avatar Russ Cox

gc: fix some spurious leaks

Probably will spark some discussion.  

R=lvd
CC=golang-dev
https://golang.org/cl/4948041
parent 8511ed45
...@@ -148,7 +148,7 @@ esc(Node *n) ...@@ -148,7 +148,7 @@ esc(Node *n)
lno = setlineno(n); lno = setlineno(n);
if(n->op == OFOR) if(n->op == OFOR || n->op == ORANGE)
loopdepth++; loopdepth++;
esclist(n->ninit); esclist(n->ninit);
...@@ -160,7 +160,7 @@ esc(Node *n) ...@@ -160,7 +160,7 @@ esc(Node *n)
esc(n->left); esc(n->left);
esc(n->right); esc(n->right);
if(n->op == OFOR) if(n->op == OFOR || n->op == ORANGE)
loopdepth--; loopdepth--;
if(debug['m'] > 1) if(debug['m'] > 1)
...@@ -169,13 +169,7 @@ esc(Node *n) ...@@ -169,13 +169,7 @@ esc(Node *n)
switch(n->op) { switch(n->op) {
case ODCL: case ODCL:
case ODCLFIELD: // Record loop depth at declaration.
// a declaration ties the node to the current
// function, but we already have that edge in
// curfn->dcl and will follow it explicitly in
// escflood to avoid storing redundant information
// What does have to happen here is note if the name
// is declared inside a looping scope.
if(n->left) if(n->left)
n->left->escloopdepth = loopdepth; n->left->escloopdepth = loopdepth;
break; break;
...@@ -184,28 +178,10 @@ esc(Node *n) ...@@ -184,28 +178,10 @@ esc(Node *n)
loopdepth++; loopdepth++;
break; break;
case ORANGE: // for <list> = range <right> { <nbody> } case ORANGE:
switch(n->type->etype) { // Everything but fixed array is a dereference.
case TARRAY: // i, v = range sliceorarray if(isfixedarray(n->type))
if(n->list->next) escassign(n->list->next->n, n->right);
escassign(n->list->next->n, n->right);
break;
case TMAP: // k [, v] = range map
escassign(n->list->n, n->right);
if(n->list->next)
escassign(n->list->next->n, n->right);
break;
case TCHAN: // v = range chan
escassign(n->list->n, n->right);
break;
}
loopdepth++;
esclist(n->nbody);
loopdepth--;
break;
case OSELRECV: // v := <-ch left: v right->op = ORECV
escassign(n->left, n->right);
break; break;
case OSWITCH: case OSWITCH:
...@@ -216,13 +192,6 @@ esc(Node *n) ...@@ -216,13 +192,6 @@ esc(Node *n)
escassign(ll->n->nname, n->ntest->right); escassign(ll->n->nname, n->ntest->right);
esclist(ll->n->nbody); esclist(ll->n->nbody);
} }
} else {
escassign(N, n->ntest);
for(ll=n->list; ll; ll=ll->next) { // cases
for(lr=ll->n->list; lr; lr=lr->next)
escassign(N, lr->n);
esclist(ll->n->nbody);
}
} }
break; break;
...@@ -245,7 +214,7 @@ esc(Node *n) ...@@ -245,7 +214,7 @@ esc(Node *n)
break; break;
case OSEND: // ch <- x case OSEND: // ch <- x
escassign(&theSink, n->right); // TODO: treat as *ch = x ? escassign(&theSink, n->right);
break; break;
case ODEFER: case ODEFER:
...@@ -271,16 +240,10 @@ esc(Node *n) ...@@ -271,16 +240,10 @@ esc(Node *n)
escassign(&theSink, n->left); escassign(&theSink, n->left);
break; break;
case OCOPY:
// left leaks to right, but the return value is harmless
// TODO: treat as *dst = *src, rather than as dst = src
escassign(n->left, n->right);
break;
case OAPPEND: case OAPPEND:
// See TODO for OCOPY if(!n->isddd)
for(ll=n->list->next; ll; ll=ll->next) for(ll=n->list->next; ll; ll=ll->next)
escassign(n->list->n, ll->n); escassign(&theSink, ll->n); // lose track of assign to dereference
break; break;
case OCALLMETH: case OCALLMETH:
...@@ -328,32 +291,47 @@ escassign(Node *dst, Node *src) ...@@ -328,32 +291,47 @@ escassign(Node *dst, Node *src)
print("%L:[%d] %#S escassign: %hN = %hN\n", lineno, loopdepth, print("%L:[%d] %#S escassign: %hN = %hN\n", lineno, loopdepth,
(curfn && curfn->nname) ? curfn->nname->sym : S, dst, src); (curfn && curfn->nname) ? curfn->nname->sym : S, dst, src);
// the lhs of an assignment needs recursive analysis too
// these are the only interesting cases
// todo:check channel case
setlineno(dst); setlineno(dst);
// Analyze lhs of assignment.
// Replace dst with theSink if we can't track it.
switch(dst->op) { switch(dst->op) {
case OINDEX: default:
case OSLICE: dump("dst", dst);
// slice: "dst[x] = src" is like *(underlying array)[x] = src fatal("escassign: unexpected dst");
// TODO maybe this never occurs b/c of OSLICEARR and it's inserted OADDR
if(!isfixedarray(dst->left->type)) case OARRAYLIT:
goto doref; case OCLOSURE:
// fallthrough; treat "dst[x] = src" as "dst = src" case OCONV:
case OCONVIFACE:
case OCONVNOP:
case OMAPLIT:
case OSTRUCTLIT:
break;
case ONAME:
if(dst->class == PEXTERN)
dst = &theSink;
break;
case ODOT: // treat "dst.x = src" as "dst = src" case ODOT: // treat "dst.x = src" as "dst = src"
escassign(dst->left, src); escassign(dst->left, src);
return; return;
case OINDEXMAP: case OINDEX:
escassign(&theSink, dst->right); // map key is put in map if(isfixedarray(dst->left->type)) {
// fallthrough escassign(dst->left, src);
return;
}
dst = &theSink; // lose track of dereference
break;
case OIND: case OIND:
case ODOTPTR: case ODOTPTR:
case OSLICEARR: // ->left is the OADDR of the array dst = &theSink; // lose track of dereference
doref: break;
// assignment to dereferences: for now we lose track case OINDEXMAP:
escassign(&theSink, src); // lose track of key and value
return; escassign(&theSink, dst->right);
dst = &theSink;
break;
} }
if(src->typecheck == 0 && src->op != OKEY) { if(src->typecheck == 0 && src->op != OKEY) {
...@@ -380,10 +358,23 @@ escassign(Node *dst, Node *src) ...@@ -380,10 +358,23 @@ escassign(Node *dst, Node *src)
case ODOT: case ODOT:
case ODOTTYPE: case ODOTTYPE:
case ODOTTYPE2: case ODOTTYPE2:
case OSLICE:
case OSLICEARR:
// Conversions, field access, slice all preserve the input value. // Conversions, field access, slice all preserve the input value.
escassign(dst, src->left); escassign(dst, src->left);
break; break;
case OAPPEND:
// Append returns first argument.
escassign(dst, src->list->n);
break;
case OINDEX:
// Index of array preserves input value.
if(isfixedarray(src->left->type))
escassign(dst, src->left);
break;
case OARRAYLIT: case OARRAYLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
case OMAPLIT: case OMAPLIT:
...@@ -410,20 +401,6 @@ escassign(Node *dst, Node *src) ...@@ -410,20 +401,6 @@ escassign(Node *dst, Node *src)
escflows(dst, src); escflows(dst, src);
escfunc(src); escfunc(src);
break; break;
// end of the leaf cases. no calls to escflows() in the cases below.
case OAPPEND:
escassign(dst, src->list->n);
break;
case OSLICEARR: // like an implicit OIND to the underlying buffer, but typecheck has inserted an OADDR
case OSLICESTR:
case OSLICE:
case OINDEX:
case OINDEXMAP:
// the big thing flows, the keys just need checking
escassign(dst, src->left);
break;
} }
pdepth--; pdepth--;
...@@ -525,10 +502,6 @@ escflows(Node *dst, Node *src) ...@@ -525,10 +502,6 @@ escflows(Node *dst, Node *src)
if(debug['m']>2) if(debug['m']>2)
print("%L::flows:: %hN <- %hN\n", lineno, dst, src); print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
// Assignments to global variables get lumped into theSink.
if(dst->op == ONAME && dst->class == PEXTERN)
dst = &theSink;
if(dst->escflowsrc == nil) { if(dst->escflowsrc == nil) {
dsts = list(dsts, dst); dsts = list(dsts, dst);
dstcount++; dstcount++;
......
...@@ -613,3 +613,89 @@ func foo92(x *int) [2]*int { // ERROR "leaking param: NAME-x" ...@@ -613,3 +613,89 @@ func foo92(x *int) [2]*int { // ERROR "leaking param: NAME-x"
return [2]*int{ x, nil } return [2]*int{ x, nil }
} }
// does not leak c
func foo93(c chan *int) *int {
for v := range c {
return v
}
return nil
}
// does not leak m
func foo94(m map[*int]*int, b bool) *int {
for k, v := range m {
if b {
return k
}
return v
}
return nil
}
// does leak x
func foo95(m map[*int]*int, x *int) { // ERROR "leaking param: NAME-x"
m[x] = x
}
// does not leak m
func foo96(m []*int) *int {
return m[0]
}
// does leak m
func foo97(m [1]*int) *int { // ERROR "leaking param: NAME-m"
return m[0]
}
// does not leak m
func foo98(m map[int]*int) *int {
return m[0]
}
// does leak m
func foo99(m *[1]*int) []*int { // ERROR "leaking param: NAME-m"
return m[:]
}
// does not leak m
func foo100(m []*int) *int {
for _, v := range m {
return v
}
return nil
}
// does leak m
func foo101(m [1]*int) *int { // ERROR "leaking param: NAME-m"
for _, v := range m {
return v
}
return nil
}
// does leak x
func foo102(m []*int, x *int) { // ERROR "leaking param: NAME-x"
m[0] = x
}
// does not leak x
func foo103(m [1]*int, x *int) {
m[0] = x
}
var y []*int
// does not leak x
func foo104(x []*int) {
copy(y, x)
}
// does not leak x
func foo105(x []*int) {
_ = append(y, x...)
}
// does leak x
func foo106(x *int) { // ERROR "leaking param: NAME-x"
_ = append(y, x)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment