From: Russ Cox Date: Fri, 14 Feb 2014 05:38:24 +0000 (-0500) Subject: cmd/gc: correct liveness for various non-returning functions X-Git-Tag: go1.3beta1~701 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=af545660d59edeffb52b8b72bec08f8c7b33cf23;p=gostls13.git cmd/gc: correct liveness for various non-returning functions When the liveness code doesn't know a function doesn't return (but the generated code understands that), the liveness analysis invents a control flow edge that is not really there, which can cause variables to seem spuriously live. This is particularly bad when the variables are uninitialized. TBR=iant CC=golang-codereviews https://golang.org/cl/63720043 --- diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c index 7fcf5db10d..1f0bdb496a 100644 --- a/src/cmd/gc/popt.c +++ b/src/cmd/gc/popt.c @@ -51,6 +51,9 @@ noreturn(Prog *p) symlist[2] = pkglookup("throwinit", runtimepkg); symlist[3] = pkglookup("panic", runtimepkg); symlist[4] = pkglookup("panicwrap", runtimepkg); + symlist[5] = pkglookup("throwreturn", runtimepkg); + symlist[6] = pkglookup("selectgo", runtimepkg); + symlist[7] = pkglookup("block", runtimepkg); } if(p->to.node == nil) diff --git a/test/live.go b/test/live.go index 032d39812d..9c4e754c17 100644 --- a/test/live.go +++ b/test/live.go @@ -121,3 +121,64 @@ func f10() string { panic(1) } +// liveness formerly confused by select, thinking runtime.selectgo +// can return to next instruction; it always jumps elsewhere. +// note that you have to use at least two cases in the select +// to get a true select; smaller selects compile to optimized helper functions. + +var c chan *int +var b bool + +// this used to have a spurious "live at entry to f11a: ~r0" +func f11a() *int { + select { // ERROR "live at call to selectgo: autotmp" + case <-c: // ERROR "live at call to selectrecv: autotmp" + return nil + case <-c: // ERROR "live at call to selectrecv: autotmp" + return nil + } +} + +func f11b() *int { + p := new(int) + if b { + // At this point p is dead: the code here cannot + // get to the bottom of the function. + // This used to have a spurious "live at call to printint: p". + print(1) // nothing live here! + select { // ERROR "live at call to selectgo: autotmp" + case <-c: // ERROR "live at call to selectrecv: autotmp" + return nil + case <-c: // ERROR "live at call to selectrecv: autotmp" + return nil + } + } + println(*p) + return nil +} + +func f11c() *int { + p := new(int) + if b { + // Unlike previous, the cases in this select fall through, + // so we can get to the println, so p is not dead. + print(1) // ERROR "live at call to printint: p" + select { // ERROR "live at call to newselect: p" "live at call to selectgo: autotmp.* p" + case <-c: // ERROR "live at call to selectrecv: autotmp.* p" + case <-c: // ERROR "live at call to selectrecv: autotmp.* p" + } + } + println(*p) + return nil +} + +// similarly, select{} does not fall through. +// this used to have a spurious "live at entry to f12: ~r0". + +func f12() *int { + if b { + select{} + } else { + return nil + } +}