]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: remove an incorrect assertion in escape analysis.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 20 Dec 2012 22:27:28 +0000 (23:27 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 20 Dec 2012 22:27:28 +0000 (23:27 +0100)
A fatal error used to happen when escassign-ing a multiple
function return to a single node. However, the situation
naturally appears when using "go f(g())" or "defer f(g())",
because g() is escassign-ed to sink.

Fixes #4529.

R=golang-dev, lvd, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6920060

src/cmd/gc/esc.c
test/escape2.go
test/fixedbugs/issue4529.go [new file with mode: 0644]

index f067cc5305371510049658d39461603695aea2cb..a313e8522f12bb772b258d4b718def7bc517b229 100644 (file)
@@ -639,6 +639,7 @@ static void
 escassign(EscState *e, Node *dst, Node *src)
 {
        int lno;
+       NodeList *ll;
 
        if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
                return;
@@ -715,9 +716,10 @@ escassign(EscState *e, Node *dst, Node *src)
        case OCALLMETH:
        case OCALLFUNC:
        case OCALLINTER:
-               if(count(src->escretval) != 1)
-                       fatal("escassign from call %+N", src);
-               escflows(e, dst, src->escretval->n);
+               // Flowing multiple returns to a single dst happens when
+               // analyzing "go f(g())": here g() flows to sink (issue 4529).
+               for(ll=src->escretval; ll; ll=ll->next)
+                       escflows(e, dst, ll->n);
                break;
 
        case ODOT:
index bfc90ecb411511563ec500731f48a3b7d7a9cf0d..6c39566feca87c3b5be63b5a55407e941a72aca4 100644 (file)
@@ -142,13 +142,13 @@ func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
 }
 
 func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
-       v := 0  // ERROR "moved to heap: v"
+       v := 0    // ERROR "moved to heap: v"
        b.ii = &v // ERROR "&v escapes"
        return b.ii
 }
 
 func (b *Bar) LeaksABit() *int { // ERROR "b does not escape"
-       v := 0  // ERROR "moved to heap: v"
+       v := 0    // ERROR "moved to heap: v"
        b.ii = &v // ERROR "&v escapes"
        return b.ii
 }
@@ -574,7 +574,7 @@ func foo75esc(z *int) { // ERROR "leaking param: z"
 }
 
 func foo75aesc(z *int) { // ERROR "z does not escape"
-       var ppi **interface{}   // assignments to pointer dereferences lose track
+       var ppi **interface{}       // assignments to pointer dereferences lose track
        *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 }
 
@@ -660,6 +660,21 @@ func foo81() *int {
        return nil
 }
 
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
+
+func noop(x, y *int) {} // ERROR "does not escape"
+
+func foo82() {
+       var x, y, z int  // ERROR "moved to heap"
+       go noop(tee(&z)) // ERROR "&z escapes to heap"
+       go noop(&x, &y)  // ERROR "escapes to heap"
+       for {
+               var u, v, w int     // ERROR "moved to heap"
+               defer noop(tee(&u)) // ERROR "&u escapes to heap"
+               defer noop(&v, &w)  // ERROR "escapes to heap"
+       }
+}
+
 type Fooer interface {
        Foo()
 }
@@ -1093,29 +1108,29 @@ L1:
        _ = i
 }
 
-func foo124(x **int) { // ERROR "x does not escape"
-       var i int       // ERROR "moved to heap: i"
-       p := &i         // ERROR "&i escapes"
-       func() {        // ERROR "func literal does not escape"
-               *x = p  // ERROR "leaking closure reference p"
+func foo124(x **int) { // ERROR "x does not escape"
+       var i int // ERROR "moved to heap: i"
+       p := &i   // ERROR "&i escapes"
+       func() {  // ERROR "func literal does not escape"
+               *x = p // ERROR "leaking closure reference p"
        }()
 }
 
-func foo125(ch chan *int) {    // ERROR "does not escape"
-       var i int       // ERROR "moved to heap"
-       p := &i         // ERROR "&i escapes to heap"
-       func() {        // ERROR "func literal does not escape"
-               ch <- p // ERROR "leaking closure reference p"
+func foo125(ch chan *int) { // ERROR "does not escape"
+       var i int // ERROR "moved to heap"
+       p := &i   // ERROR "&i escapes to heap"
+       func() {  // ERROR "func literal does not escape"
+               ch <- p // ERROR "leaking closure reference p"
        }()
 }
 
 func foo126() {
-       var px *int  // loopdepth 0
+       var px *int // loopdepth 0
        for {
                // loopdepth 1
-               var i int  // ERROR "moved to heap"
+               var i int // ERROR "moved to heap"
                func() {  // ERROR "func literal does not escape"
-                       px = &i  // ERROR "&i escapes"
+                       px = &i // ERROR "&i escapes"
                }()
        }
 }
@@ -1123,8 +1138,8 @@ func foo126() {
 var px *int
 
 func foo127() {
-       var i int  // ERROR "moved to heap: i"
-       p := &i  // ERROR "&i escapes to heap"
+       var i int // ERROR "moved to heap: i"
+       p := &i   // ERROR "&i escapes to heap"
        q := p
        px = q
 }
@@ -1137,12 +1152,12 @@ func foo128() {
 }
 
 func foo129() {
-       var i int  // ERROR "moved to heap: i"
-       p := &i  // ERROR "&i escapes to heap"
+       var i int // ERROR "moved to heap: i"
+       p := &i   // ERROR "&i escapes to heap"
        func() {  // ERROR "func literal does not escape"
-               q := p  // ERROR "leaking closure reference p"
-               func() {  // ERROR "func literal does not escape"
-                       r := q  // ERROR "leaking closure reference q"
+               q := p   // ERROR "leaking closure reference p"
+               func() { // ERROR "func literal does not escape"
+                       r := q // ERROR "leaking closure reference q"
                        px = r
                }()
        }()
@@ -1150,40 +1165,40 @@ func foo129() {
 
 func foo130() {
        for {
-               var i int  // ERROR "moved to heap"
+               var i int // ERROR "moved to heap"
                func() {  // ERROR "func literal does not escape"
-                       px = &i  // ERROR "&i escapes" "leaking closure reference i"
+                       px = &i // ERROR "&i escapes" "leaking closure reference i"
                }()
        }
 }
 
 func foo131() {
-       var i int  // ERROR "moved to heap"
+       var i int // ERROR "moved to heap"
        func() {  // ERROR "func literal does not escape"
-               px = &i  // ERROR "&i escapes" "leaking closure reference i"
+               px = &i // ERROR "&i escapes" "leaking closure reference i"
        }()
 }
 
 func foo132() {
-       var i int  // ERROR "moved to heap"
-       go func() {  // ERROR "func literal escapes to heap"
-               px = &i  // ERROR "&i escapes" "leaking closure reference i"
+       var i int   // ERROR "moved to heap"
+       go func() { // ERROR "func literal escapes to heap"
+               px = &i // ERROR "&i escapes" "leaking closure reference i"
        }()
 }
 
 func foo133() {
-       var i int  // ERROR "moved to heap"
-       defer func() {  // ERROR "func literal does not escape"
-               px = &i  // ERROR "&i escapes" "leaking closure reference i"
+       var i int      // ERROR "moved to heap"
+       defer func() { // ERROR "func literal does not escape"
+               px = &i // ERROR "&i escapes" "leaking closure reference i"
        }()
 }
 
 func foo134() {
        var i int
        p := &i  // ERROR "&i does not escape"
-       func() {  // ERROR "func literal does not escape"
+       func() { // ERROR "func literal does not escape"
                q := p
-               func() {  // ERROR "func literal does not escape"
+               func() { // ERROR "func literal does not escape"
                        r := q
                        _ = r
                }()
@@ -1191,11 +1206,11 @@ func foo134() {
 }
 
 func foo135() {
-       var i int  // ERROR "moved to heap: i"
-       p := &i  // ERROR "&i escapes to heap" "moved to heap: p"
-       go func() {  // ERROR "func literal escapes to heap"
-               q := p  // ERROR "&p escapes to heap"
-               func() {  // ERROR "func literal does not escape"
+       var i int   // ERROR "moved to heap: i"
+       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       go func() { // ERROR "func literal escapes to heap"
+               q := p   // ERROR "&p escapes to heap"
+               func() { // ERROR "func literal does not escape"
                        r := q
                        _ = r
                }()
@@ -1203,11 +1218,11 @@ func foo135() {
 }
 
 func foo136() {
-       var i int  // ERROR "moved to heap: i"
-       p := &i  // ERROR "&i escapes to heap" "moved to heap: p"
-       go func() {  // ERROR "func literal escapes to heap"
-               q := p  // ERROR "&p escapes to heap" "leaking closure reference p"
-               func() {  // ERROR "func literal does not escape"
+       var i int   // ERROR "moved to heap: i"
+       p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+       go func() { // ERROR "func literal escapes to heap"
+               q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
+               func() { // ERROR "func literal does not escape"
                        r := q // ERROR "leaking closure reference q"
                        px = r
                }()
@@ -1215,12 +1230,12 @@ func foo136() {
 }
 
 func foo137() {
-       var i int  // ERROR "moved to heap: i"
-       p := &i  // ERROR "&i escapes to heap"
+       var i int // ERROR "moved to heap: i"
+       p := &i   // ERROR "&i escapes to heap"
        func() {  // ERROR "func literal does not escape"
-               q := p  // ERROR "leaking closure reference p" "moved to heap: q"
+               q := p      // ERROR "leaking closure reference p" "moved to heap: q"
                go func() { // ERROR "func literal escapes to heap"
-                       r := q  // ERROR "&q escapes to heap"
+                       r := q // ERROR "&q escapes to heap"
                        _ = r
                }()
        }()
@@ -1230,7 +1245,7 @@ func foo138() *byte {
        type T struct {
                x [1]byte
        }
-       t := new(T) // ERROR "new.T. escapes to heap"
+       t := new(T)    // ERROR "new.T. escapes to heap"
        return &t.x[0] // ERROR "&t.x.0. escapes to heap"
 }
 
@@ -1240,6 +1255,6 @@ func foo139() *byte {
                        y byte
                }
        }
-       t := new(T) // ERROR "new.T. escapes to heap"
+       t := new(T)   // ERROR "new.T. escapes to heap"
        return &t.x.y // ERROR "&t.x.y escapes to heap"
 }
diff --git a/test/fixedbugs/issue4529.go b/test/fixedbugs/issue4529.go
new file mode 100644 (file)
index 0000000..4f37e7c
--- /dev/null
@@ -0,0 +1,33 @@
+// compile
+
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 4529: escape analysis crashes on "go f(g())"
+// when g has multiple returns.
+
+package main
+
+type M interface{}
+
+type A struct {
+       a string
+       b chan M
+}
+
+func (a *A) I() (b <-chan M, c chan<- M) {
+       a.b, c = make(chan M), make(chan M)
+       b = a.b
+
+       return
+}
+
+func Init(a string, b *A, c interface {
+       I() (<-chan M, chan<- M)
+}) {
+       b.a = a
+       go b.c(c.I())
+}
+
+func (a *A) c(b <-chan M, _ chan<- M) {}