From 1dcf658f6dbc6b09ead3fb7561cd1832d9a697a1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9my=20Oudompheng?= Date: Thu, 20 Dec 2012 23:27:28 +0100 Subject: [PATCH] cmd/gc: remove an incorrect assertion in escape analysis. 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 | 8 ++- test/escape2.go | 117 ++++++++++++++++++++---------------- test/fixedbugs/issue4529.go | 33 ++++++++++ 3 files changed, 104 insertions(+), 54 deletions(-) create mode 100644 test/fixedbugs/issue4529.go diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index f067cc5305..a313e8522f 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -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: diff --git a/test/escape2.go b/test/escape2.go index bfc90ecb41..6c39566fec 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -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 index 0000000000..4f37e7c36b --- /dev/null +++ b/test/fixedbugs/issue4529.go @@ -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) {} -- 2.48.1