diff --git a/test/escape2.go b/test/escape2.go index e3561a0f60b..f682621c255 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -121,7 +121,7 @@ func NewBar() *Bar { return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" } -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" +func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } @@ -758,7 +758,7 @@ type LimitedFooer struct { N int64 } -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" } @@ -1360,7 +1360,7 @@ func F2([]byte) func F3(x []byte) // ERROR "F3 x does not escape$" -func F4(x []byte) +func F4(x []byte) // ERROR "leaking param: x$" func G() { var buf1 [10]byte @@ -1529,8 +1529,7 @@ type V struct { s *string } -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" +func NewV(u U) *V { // ERROR "leaking param: u$" return &V{u.String()} // ERROR "&V literal escapes to heap$" } @@ -1543,7 +1542,7 @@ func foo152() { // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" +func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" return &x @@ -1806,7 +1805,7 @@ func issue10353() { issue10353a(x)() } -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" +func issue10353a(x *int) func() { // ERROR "leaking param: x$" return func() { // ERROR "func literal escapes to heap$" println(*x) } diff --git a/test/escape2n.go b/test/escape2n.go index 6ec198fd325..2fd26f7c5c5 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l +// errorcheck -0 -N -m -l -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -121,7 +121,7 @@ func NewBar() *Bar { return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" } -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" +func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } @@ -758,7 +758,7 @@ type LimitedFooer struct { N int64 } -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" } @@ -1360,7 +1360,7 @@ func F2([]byte) func F3(x []byte) // ERROR "F3 x does not escape$" -func F4(x []byte) +func F4(x []byte) // ERROR "leaking param: x$" func G() { var buf1 [10]byte @@ -1529,8 +1529,7 @@ type V struct { s *string } -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" +func NewV(u U) *V { // ERROR "leaking param: u$" return &V{u.String()} // ERROR "&V literal escapes to heap$" } @@ -1543,7 +1542,7 @@ func foo152() { // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" +func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" return &x @@ -1806,7 +1805,7 @@ func issue10353() { issue10353a(x)() } -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" +func issue10353a(x *int) func() { // ERROR "leaking param: x$" return func() { // ERROR "func literal escapes to heap$" println(*x) } diff --git a/test/escape5.go b/test/escape5.go index 4dbe89f313d..393a4b0ac4f 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -129,7 +129,7 @@ type T2 struct { Y *T1 } -func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p" +func f8(p *T1) (k T2) { // ERROR "leaking param: p$" if p == nil { k = T2{} return diff --git a/test/escape_because.go b/test/escape_because.go index 7ba5d679a11..e0a4214e7c7 100644 --- a/test/escape_because.go +++ b/test/escape_because.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -m -l +// errorcheck -0 -m -m -l -newescape=false // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/escape_calls.go b/test/escape_calls.go index 186c6f80989..53f14dffd3f 100644 --- a/test/escape_calls.go +++ b/test/escape_calls.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -36,7 +36,7 @@ func walk(np **Node) int { // ERROR "leaking param content: np" wl := walk(&n.left) wr := walk(&n.right) if wl < wr { - n.left, n.right = n.right, n.left + n.left, n.right = n.right, n.left // ERROR "ignoring self-assignment" wl, wr = wr, wl } *np = n diff --git a/test/escape_closure.go b/test/escape_closure.go index 93efe94ed78..cf055d3b345 100644 --- a/test/escape_closure.go +++ b/test/escape_closure.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,27 +11,24 @@ package escape var sink interface{} func ClosureCallArgs0() { - x := 0 // ERROR "moved to heap: x" + x := 0 func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here }(&x) } func ClosureCallArgs1() { - x := 0 // ERROR "moved to heap: x" + x := 0 for { func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here }(&x) } } func ClosureCallArgs2() { for { - // BAD: x should not escape here - x := 0 // ERROR "moved to heap: x" + x := 0 func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 }(&x) @@ -46,8 +43,7 @@ func ClosureCallArgs3() { } func ClosureCallArgs4() { - // BAD: x should not leak here - x := 0 // ERROR "moved to heap: x" + x := 0 _ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" return p }(&x) @@ -55,7 +51,9 @@ func ClosureCallArgs4() { func ClosureCallArgs5() { x := 0 // ERROR "moved to heap: x" - sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" + // TODO(mdempsky): We get "leaking param: p" here because the new escape analysis pass + // can tell that p flows directly to sink, but it's a little weird. Re-evaluate. + sink = func(p *int) *int { // ERROR "leaking param: p" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" return p }(&x) } @@ -79,10 +77,9 @@ func ClosureCallArgs7() { } func ClosureCallArgs8() { - x := 0 // ERROR "moved to heap: x" + x := 0 defer func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here }(&x) } @@ -113,8 +110,7 @@ func ClosureCallArgs11() { } func ClosureCallArgs12() { - // BAD: x should not leak - x := 0 // ERROR "moved to heap: x" + x := 0 defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" return p }(&x) @@ -128,21 +124,18 @@ func ClosureCallArgs13() { } func ClosureCallArgs14() { - x := 0 // ERROR "moved to heap: x" - // BAD: &x should not escape here - p := &x // ERROR "moved to heap: p" + x := 0 + p := &x _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" return *p - // BAD: p should not escape here }(&p) } func ClosureCallArgs15() { x := 0 // ERROR "moved to heap: x" - p := &x // ERROR "moved to heap: p" - sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" + p := &x + sink = func(p **int) *int { // ERROR "leaking param content: p" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" return *p - // BAD: p should not escape here }(&p) } @@ -152,7 +145,7 @@ func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" } // See #14409 -- returning part of captured var leaks it. -func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1$" return func() string { // ERROR "ClosureLeak1a func literal does not escape" return a[0] }() @@ -163,11 +156,11 @@ func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" return c } -func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" +func ClosureLeak2a(a ...string) string { // ERROR "leaking param content: a" return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" return a[0] }) } -func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" +func ClosureLeak2b(f func() string) string { // ERROR "ClosureLeak2b f does not escape" return f() } diff --git a/test/escape_field.go b/test/escape_field.go index ae2425871f6..5d5a6f36b4f 100644 --- a/test/escape_field.go +++ b/test/escape_field.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -149,7 +149,7 @@ func field16() { var x X // BAD: &i should not escape x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" + var iface interface{} = x // ERROR "field16 x does not escape" x1 := iface.(X) sink = x1.p2 // ERROR "x1\.p2 escapes to heap" } @@ -158,7 +158,7 @@ func field17() { i := 0 // ERROR "moved to heap: i$" var x X x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" + var iface interface{} = x // ERROR "field17 x does not escape" x1 := iface.(X) sink = x1.p1 // ERROR "x1\.p1 escapes to heap" } @@ -168,7 +168,7 @@ func field18() { var x X // BAD: &i should not escape x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" + var iface interface{} = x // ERROR "field18 x does not escape" y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized. sink = y // ERROR "y escapes to heap" } diff --git a/test/escape_iface.go b/test/escape_iface.go index 2a08547165e..50c69cd5c10 100644 --- a/test/escape_iface.go +++ b/test/escape_iface.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -110,8 +110,7 @@ func efaceEscape1() { { i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} - // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" + var x M = v // ERROR "efaceEscape1 v does not escape" v1 := x.(M1) sink = v1 // ERROR "v1 escapes to heap" } diff --git a/test/escape_param.go b/test/escape_param.go index 0a81e8c9c86..20975567449 100644 --- a/test/escape_param.go +++ b/test/escape_param.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -415,7 +415,7 @@ func f(x *Node) { // ERROR "leaking param content: x" Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" } -func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0" +func g(x *Node) *Node { // ERROR "leaking param content: x" return &Node{x.p} // ERROR "&Node literal escapes to heap" } diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go index 8a9e0963fa6..2b6de1c76af 100644 --- a/test/escape_struct_return.go +++ b/test/escape_struct_return.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -19,7 +19,7 @@ func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 l return U{sp, spp} } -func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$" +func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" return U{*spp, spp} } diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go index 4a64e5416ee..adbbb28b1b6 100644 --- a/test/fixedbugs/issue12006.go +++ b/test/fixedbugs/issue12006.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -23,7 +23,7 @@ func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking var sink []*int -func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" "leaking param content: vals" +func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" vals = append(vals, x) sink = vals return FooN(vals...) diff --git a/test/fixedbugs/issue17318.go b/test/fixedbugs/issue17318.go index fe00859bd7d..f8755175421 100644 --- a/test/fixedbugs/issue17318.go +++ b/test/fixedbugs/issue17318.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l +// errorcheck -0 -N -m -l -newescape=true // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -26,8 +26,8 @@ func (e ent) String() string { } //go:noinline -func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$" - enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$" +func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "foo ops does not escape" + enqueue := func(i int) fmt.Stringer { // ERROR "foo func literal does not escape" return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" } err = enqueue(4) @@ -39,7 +39,7 @@ func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" func main() { // 3 identical functions, to get different escape behavior. - f := func(i, j int) ent { // ERROR "func literal escapes to heap$" + f := func(i, j int) ent { // ERROR "main func literal does not escape" return ent(i + j) } i := foo(f, 3).(ent) diff --git a/test/fixedbugs/oldescape_issue12006.go b/test/fixedbugs/oldescape_issue12006.go new file mode 100644 index 00000000000..0697f58b643 --- /dev/null +++ b/test/fixedbugs/oldescape_issue12006.go @@ -0,0 +1,174 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis through ... parameters. + +package foo + +func FooN(vals ...*int) (s int) { // ERROR "FooN vals does not escape" + for _, v := range vals { + s += *v + } + return s +} + +// Append forces heap allocation and copies entries in vals to heap, therefore they escape to heap. +func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param content: vals" + vals = append(vals, x) + return FooN(vals...) +} + +var sink []*int + +func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" "leaking param content: vals" + vals = append(vals, x) + sink = vals + return FooN(vals...) +} + +func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals" + sink = vals + return FooN(vals...) +} + +func TFooN() { + for i := 0; i < 1000; i++ { + var i, j int + FooN(&i, &j) // ERROR "TFooN ... argument does not escape" + } +} + +func TFooNx() { + for i := 0; i < 1000; i++ { + var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" + FooNx(&k, &i, &j) // ERROR "TFooNx ... argument does not escape" + } +} + +func TFooNy() { + for i := 0; i < 1000; i++ { + var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" + FooNy(&k, &i, &j) // ERROR "... argument escapes to heap" + } +} + +func TFooNz() { + for i := 0; i < 1000; i++ { + var i, j int // ERROR "moved to heap: i" "moved to heap: j" + FooNz(&i, &j) // ERROR "... argument escapes to heap" + } +} + +var isink *int32 + +func FooI(args ...interface{}) { // ERROR "leaking param content: args" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + isink = x + case string: + println("is string") + } + } +} + +func TFooI() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooI ... argument does not escape" +} + +func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooJ1() { + a := int32(1) + b := "cat" + c := &a + FooJ(a, b, c) // ERROR "TFooJ1 a does not escape" "TFooJ1 b does not escape" "TFooJ1 c does not escape" "TFooJ1 ... argument does not escape" +} + +func TFooJ2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooJ2 ... argument does not escape" +} + +type fakeSlice struct { + l int + a *[4]interface{} +} + +func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < args.l; i++ { + switch x := (*args.a)[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooK2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooK2 &\[4\]interface {} literal does not escape" + isink = FooK(fs) +} + +func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooL2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooL2 \[\]interface {} literal does not escape" + isink = FooL(s) +} diff --git a/test/fixedbugs/oldescape_issue17318.go b/test/fixedbugs/oldescape_issue17318.go new file mode 100644 index 00000000000..10084ba8127 --- /dev/null +++ b/test/fixedbugs/oldescape_issue17318.go @@ -0,0 +1,47 @@ +// errorcheck -0 -N -m -l -newescape=false + +// Copyright 2016 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. + +// The escape analyzer needs to run till its root set settles +// (this is not that often, it turns out). +// This test is likely to become stale because the leak depends +// on a spurious-escape bug -- return an interface as a named +// output parameter appears to cause the called closure to escape, +// where returning it as a regular type does not. + +package main + +import ( + "fmt" +) + +type closure func(i, j int) ent + +type ent int + +func (e ent) String() string { + return fmt.Sprintf("%d", int(e)) // ERROR "ent.String ... argument does not escape$" "int\(e\) escapes to heap$" +} + +//go:noinline +func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$" + enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$" + return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" + } + err = enqueue(4) + if err != nil { + return err + } + return // return result of enqueue, a fmt.Stringer +} + +func main() { + // 3 identical functions, to get different escape behavior. + f := func(i, j int) ent { // ERROR "func literal escapes to heap$" + return ent(i + j) + } + i := foo(f, 3).(ent) + fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "main ... argument does not escape$" +} diff --git a/test/linkname.dir/linkname2.go b/test/linkname.dir/linkname2.go index 5df4f50ff2c..9323ac5f1ee 100644 --- a/test/linkname.dir/linkname2.go +++ b/test/linkname.dir/linkname2.go @@ -3,7 +3,7 @@ package y import _ "unsafe" //go:linkname byteIndex linkname1.indexByte -func byteIndex(xs []byte, b byte) int +func byteIndex(xs []byte, b byte) int // ERROR "leaking param: xs" func ContainsSlash(data []byte) bool { // ERROR "leaking param: data" "can inline ContainsSlash" if byteIndex(data, '/') != -1 { diff --git a/test/linkname.go b/test/linkname.go index c94a113c90f..8e79b51b9b9 100644 --- a/test/linkname.go +++ b/test/linkname.go @@ -1,4 +1,4 @@ -// errorcheckandrundir -0 -m -l=4 +// errorcheckandrundir -0 -m -l=4 -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/oldescape2.go b/test/oldescape2.go new file mode 100644 index 00000000000..864a956164f --- /dev/null +++ b/test/oldescape2.go @@ -0,0 +1,1847 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2010 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. + +// Test, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. + +// escape2n.go contains all the same tests but compiles with -N. + +package foo + +import ( + "fmt" + "unsafe" +) + +var gxx *int + +func foo1(x int) { // ERROR "moved to heap: x$" + gxx = &x +} + +func foo2(yy *int) { // ERROR "leaking param: yy$" + gxx = yy +} + +func foo3(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +type T *T + +func foo3b(t T) { // ERROR "leaking param: t$" + *t = t +} + +// xx isn't going anywhere, so use of yy is ok +func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" + xx = yy +} + +// xx isn't going anywhere, so taking address of yy is ok +func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" + xx = &yy +} + +func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" + *xx = yy +} + +func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" + **xx = *yy +} + +func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" + xx = yy + return *xx +} + +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" + xx = yy + return xx +} + +func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" + *xx = *yy +} + +func foo11() int { + x, y := 0, 42 + xx := &x + yy := &y + *xx = *yy + return x +} + +var xxx **int + +func foo12(yyy **int) { // ERROR "leaking param: yyy$" + xxx = yyy +} + +// Must treat yyy as leaking because *yyy leaks, and the escape analysis +// summaries in exported metadata do not distinguish these two cases. +func foo13(yyy **int) { // ERROR "leaking param content: yyy$" + *xxx = *yyy +} + +func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" + **xxx = **yyy +} + +func foo15(yy *int) { // ERROR "moved to heap: yy$" + xxx = &yy +} + +func foo16(yy *int) { // ERROR "leaking param: yy$" + *xxx = yy +} + +func foo17(yy *int) { // ERROR "foo17 yy does not escape$" + **xxx = *yy +} + +func foo18(y int) { // ERROR "moved to heap: y$" + *xxx = &y +} + +func foo19(y int) { + **xxx = y +} + +type Bar struct { + i int + ii *int +} + +func NewBar() *Bar { + return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" + return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" + return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" +} + +func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" + return *(b.ii) +} + +func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return &b.i +} + +func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii +} + +func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.ii +} + +func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" + v := 0 + b.ii = &v + return b.i +} + +func goLeak(b *Bar) { // ERROR "leaking param: b$" + go b.NoLeak() +} + +type Bar2 struct { + i [12]int + ii []int +} + +func NewBar2() *Bar2 { + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" +} + +func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" + return b.i[0] +} + +func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.i[:] +} + +func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii[0:1] +} + +func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" + return b.i +} + +func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" + b.ii = b.i[0:4] +} + +func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" + var buf []int + buf = b.i[0:] + b.ii = buf +} + +func foo21() func() int { + x := 42 + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo21a() func() int { + x := 42 // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo22() int { + x := 42 + return func() int { // ERROR "foo22 func literal does not escape$" + return x + }() +} + +func foo23(x int) func() int { + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo23a(x int) func() int { + f := func() int { // ERROR "func literal escapes to heap$" + return x + } + return f +} + +func foo23b(x int) *(func() int) { + f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" + return &f +} + +func foo23c(x int) func() int { // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo24(x int) int { + return func() int { // ERROR "foo24 func literal does not escape$" + return x + }() +} + +var x *int + +func fooleak(xx *int) int { // ERROR "leaking param: xx$" + x = xx + return *x +} + +func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" + return *x + *xx +} + +func foo31(x int) int { // ERROR "moved to heap: x$" + return fooleak(&x) +} + +func foo32(x int) int { + return foonoleak(&x) +} + +type Foo struct { + xx *int + x int +} + +var F Foo +var pf *Foo + +func (f *Foo) fooleak() { // ERROR "leaking param: f$" + pf = f +} + +func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" + F.x = f.x +} + +func (f *Foo) Leak() { // ERROR "leaking param: f$" + f.fooleak() +} + +func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" + f.foonoleak() +} + +func foo41(x int) { // ERROR "moved to heap: x$" + F.xx = &x +} + +func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo44(yy *int) { // ERROR "leaking param: yy$" + F.xx = yy +} + +func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" + F.x = f.x +} + +// See foo13 above for explanation of why f leaks. +func (f *Foo) foo46() { // ERROR "leaking param content: f$" + F.xx = f.xx +} + +func (f *Foo) foo47() { // ERROR "leaking param: f$" + f.xx = &f.x +} + +var ptrSlice []*int + +func foo50(i *int) { // ERROR "leaking param: i$" + ptrSlice[0] = i +} + +var ptrMap map[*int]*int + +func foo51(i *int) { // ERROR "leaking param: i$" + ptrMap[i] = i +} + +func indaddr1(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *&x +} + +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *(**int)(unsafe.Pointer(&x)) +} + +// From package math: + +func Float32bits(f float32) uint32 { + return *(*uint32)(unsafe.Pointer(&f)) +} + +func Float32frombits(b uint32) float32 { + return *(*float32)(unsafe.Pointer(&b)) +} + +func Float64bits(f float64) uint64 { + return *(*uint64)(unsafe.Pointer(&f)) +} + +func Float64frombits(b uint64) float64 { + return *(*float64)(unsafe.Pointer(&b)) +} + +// contrast with +func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" + return (*uint64)(unsafe.Pointer(&f)) +} + +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" + return (*uint64)(unsafe.Pointer(f)) +} + +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch val := i.(type) { + case *int: + return val + case *int8: + v := int(*val) // ERROR "moved to heap: v$" + return &v + } + return nil +} + +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch j := i; *j + 110 { + case 12: + return j + case 42: + return nil + } + return nil + +} + +// assigning to an array element is like assigning to the array +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + var a [12]*int + a[0] = i + return a[1] +} + +func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" + var a [12]*int + a[0] = i + return nil +} + +// assigning to a struct field is like assigning to the struct +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + type S struct { + a, b *int + } + var s S + s.a = i + return s.b +} + +func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" + type S struct { + a, b *int + } + var s S + s.a = i + return nil +} + +// assigning to a struct field is like assigning to the struct but +// here this subtlety is lost, since s.a counts as an assignment to a +// track-losing dereference. +func foo62(i *int) *int { // ERROR "leaking param: i$" + type S struct { + a, b *int + } + s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s.a = i + return nil // s.b +} + +type M interface { + M() +} + +func foo63(m M) { // ERROR "foo63 m does not escape$" +} + +func foo64(m M) { // ERROR "leaking param: m$" + m.M() +} + +func foo64b(m M) { // ERROR "leaking param: m$" + defer m.M() +} + +type MV int + +func (MV) M() {} + +func foo65() { + var mv MV + foo63(&mv) // ERROR "foo65 &mv does not escape$" +} + +func foo66() { + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) // ERROR "&mv escapes to heap$" +} + +func foo67() { + var mv MV + foo63(mv) // ERROR "foo67 mv does not escape$" +} + +func foo68() { + var mv MV + // escapes but it's an int so irrelevant + foo64(mv) // ERROR "mv escapes to heap$" +} + +func foo69(m M) { // ERROR "leaking param: m$" + foo64(m) +} + +func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" + m = mv1 // ERROR "mv1 escapes to heap$" + foo64(m) +} + +func foo71(x *int) []*int { // ERROR "leaking param: x$" + var y []*int + y = append(y, x) + return y +} + +func foo71a(x int) []*int { // ERROR "moved to heap: x$" + var y []*int + y = append(y, &x) + return y +} + +func foo72() { + var x int + var y [1]*int + y[0] = &x +} + +func foo72aa() [10]*int { + var x int // ERROR "moved to heap: x$" + var y [10]*int + y[0] = &x + return y +} + +func foo72a() { + var y [10]*int + for i := 0; i < 10; i++ { + // escapes its scope + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return +} + +func foo72b() [10]*int { + var y [10]*int + for i := 0; i < 10; i++ { + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return y +} + +// issue 2145 +func foo73() { + s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + println(vv) + }() + } +} + +func foo731() { + s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + vv = 42 + println(vv) + }() + } +} + +func foo74() { + s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + println(vv) + } + defer fn() + } +} + +func foo74a() { + s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + vv += 1 + println(vv) + } + defer fn() + } +} + +// issue 3975 +func foo74b() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" + for i, v := range s { + vv := v + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(vv) + } + } +} + +func foo74c() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" + for i, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(&vv) + } + } +} + +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" + return y +} + +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" + return &x[0] +} + +func foo75(z *int) { // ERROR "foo75 z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +} + +func foo75a(z *int) { // ERROR "foo75a z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +} + +func foo75esc(z *int) { // ERROR "leaking param: z$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" +} + +func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" + var ppi **interface{} // assignments to pointer dereferences lose track + *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" +} + +func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +} + +func foo76(z *int) { // ERROR "z does not escape" + myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" +} + +func foo76a(z *int) { // ERROR "z does not escape" + myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" +} + +func foo76b() { + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" +} + +func foo76c() { + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" +} + +func foo76d() { + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" +} + +func foo76e() { + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" +} + +func foo76f() { + for { + // TODO: This one really only escapes its scope, but we don't distinguish yet. + defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo76g() { + for { + defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" + myprint(nil, z...) // z does not escape +} + +func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" + myprint1(nil, z...) +} + +func foo77b(z []interface{}) { // ERROR "leaking param: z$" + var ppi **interface{} + *ppi = myprint1(nil, z...) +} + +func foo77c(z []interface{}) { // ERROR "leaking param: z$" + sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" +} + +func dotdotdot() { + i := 0 + myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + + j := 0 + myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" +} + +func foo78(z int) *int { // ERROR "moved to heap: z$" + return &z +} + +func foo78a(z int) *int { // ERROR "moved to heap: z$" + y := &z + x := &y + return *x // really return y +} + +func foo79() *int { + return new(int) // ERROR "new\(int\) escapes to heap$" +} + +func foo80() *int { + var z *int + for { + // Really just escapes its scope but we don't distinguish + z = new(int) // ERROR "new\(int\) escapes to heap$" + } + _ = z + return nil +} + +func foo81() *int { + for { + z := new(int) // ERROR "foo81 new\(int\) does not escape$" + _ = z + } + return nil +} + +func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" + +func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" + +func foo82() { + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + go noop(tee(&z)) + go noop(&x, &y) + for { + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + defer noop(tee(&u)) + defer noop(&v, &w) + } +} + +type Fooer interface { + Foo() +} + +type LimitedFooer struct { + Fooer + N int64 +} + +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" +} + +func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" + return [2]*int{x, nil} +} + +// does not leak c +func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" + for v := range c { + return v + } + return nil +} + +// does not leak m +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" + 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 "foo95 m does not escape$" "leaking param: x$" + m[x] = x +} + +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + return m[0] +} + +// does leak m +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[0] +} + +// does not leak m +func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" + return m[0] +} + +// does leak m +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[:] +} + +// does not leak m +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + for _, v := range m { + return v + } + return nil +} + +// does leak m +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + for _, v := range m { + return v + } + return nil +} + +// does not leak m +func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" + for i := range m { // ERROR "moved to heap: i$" + return &i + } + return nil +} + +// does leak x +func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" + m[0] = x +} + +// does not leak x +func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" + m[0] = x +} + +var y []*int + +// does not leak x but does leak content +func foo104(x []*int) { // ERROR "leaking param content: x" + copy(y, x) +} + +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" + _ = append(y, x...) +} + +// does leak x +func foo106(x *int) { // ERROR "leaking param: x$" + _ = append(y, x) +} + +func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo109(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + for k, _ := range m { + return k + } + return nil +} + +func foo110(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" + return m[nil] +} + +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" + m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + return m[0] +} + +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := [1]*int{x} + return m[0] +} + +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := Bar{ii: x} + return m.ii +} + +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" + return m.ii +} + +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) +} + +func foo116(b bool) *int { + if b { + x := 1 // ERROR "moved to heap: x$" + return &x + } else { + y := 1 // ERROR "moved to heap: y$" + return &y + } + return nil +} + +func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) // ERROR "&x escapes to heap$" +} + +func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) +} + +func external(*int) + +func foo119(x *int) { // ERROR "leaking param: x$" + external(x) +} + +func foo120() { + // formerly exponential time analysis +L1: +L2: +L3: +L4: +L5: +L6: +L7: +L8: +L9: +L10: +L11: +L12: +L13: +L14: +L15: +L16: +L17: +L18: +L19: +L20: +L21: +L22: +L23: +L24: +L25: +L26: +L27: +L28: +L29: +L30: +L31: +L32: +L33: +L34: +L35: +L36: +L37: +L38: +L39: +L40: +L41: +L42: +L43: +L44: +L45: +L46: +L47: +L48: +L49: +L50: +L51: +L52: +L53: +L54: +L55: +L56: +L57: +L58: +L59: +L60: +L61: +L62: +L63: +L64: +L65: +L66: +L67: +L68: +L69: +L70: +L71: +L72: +L73: +L74: +L75: +L76: +L77: +L78: +L79: +L80: +L81: +L82: +L83: +L84: +L85: +L86: +L87: +L88: +L89: +L90: +L91: +L92: +L93: +L94: +L95: +L96: +L97: +L98: +L99: +L100: + // use the labels to silence compiler errors + goto L1 + goto L2 + goto L3 + goto L4 + goto L5 + goto L6 + goto L7 + goto L8 + goto L9 + goto L10 + goto L11 + goto L12 + goto L13 + goto L14 + goto L15 + goto L16 + goto L17 + goto L18 + goto L19 + goto L20 + goto L21 + goto L22 + goto L23 + goto L24 + goto L25 + goto L26 + goto L27 + goto L28 + goto L29 + goto L30 + goto L31 + goto L32 + goto L33 + goto L34 + goto L35 + goto L36 + goto L37 + goto L38 + goto L39 + goto L40 + goto L41 + goto L42 + goto L43 + goto L44 + goto L45 + goto L46 + goto L47 + goto L48 + goto L49 + goto L50 + goto L51 + goto L52 + goto L53 + goto L54 + goto L55 + goto L56 + goto L57 + goto L58 + goto L59 + goto L60 + goto L61 + goto L62 + goto L63 + goto L64 + goto L65 + goto L66 + goto L67 + goto L68 + goto L69 + goto L70 + goto L71 + goto L72 + goto L73 + goto L74 + goto L75 + goto L76 + goto L77 + goto L78 + goto L79 + goto L80 + goto L81 + goto L82 + goto L83 + goto L84 + goto L85 + goto L86 + goto L87 + goto L88 + goto L89 + goto L90 + goto L91 + goto L92 + goto L93 + goto L94 + goto L95 + goto L96 + goto L97 + goto L98 + goto L99 + goto L100 +} + +func foo121() { + for i := 0; i < 10; i++ { + defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + go myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// same as foo121 but check across import +func foo121b() { + for i := 0; i < 10; i++ { + defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// a harmless forward jump +func foo122() { + var i *int + + goto L1 +L1: + i = new(int) // ERROR "foo122 new\(int\) does not escape$" + _ = i +} + +// a backward jump, increases loopdepth +func foo123() { + var i *int + +L1: + i = new(int) // ERROR "new\(int\) escapes to heap$" + + goto L1 + _ = i +} + +func foo124(x **int) { // ERROR "foo124 x does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo124 func literal does not escape$" + *x = p + }() +} + +func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo125 func literal does not escape$" + ch <- p + }() +} + +func foo126() { + var px *int // loopdepth 0 + for { + // loopdepth 1 + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo126 func literal does not escape$" + px = &i + }() + } + _ = px +} + +var px *int + +func foo127() { + var i int // ERROR "moved to heap: i$" + p := &i + q := p + px = q +} + +func foo128() { + var i int + p := &i + q := p + _ = q +} + +func foo129() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo129 func literal does not escape$" + q := p + func() { // ERROR "foo129.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo130() { + for { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo130 func literal does not escape$" + px = &i + }() + } +} + +func foo131() { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo131 func literal does not escape$" + px = &i + }() +} + +func foo132() { + var i int // ERROR "moved to heap: i$" + go func() { // ERROR "func literal escapes to heap$" + px = &i + }() +} + +func foo133() { + var i int // ERROR "moved to heap: i$" + defer func() { // ERROR "foo133 func literal does not escape$" + px = &i + }() +} + +func foo134() { + var i int + p := &i + func() { // ERROR "foo134 func literal does not escape$" + q := p + func() { // ERROR "foo134.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo135() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo135.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo136() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo136.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo137() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo137 func literal does not escape$" + q := p + go func() { // ERROR "func literal escapes to heap$" + r := q + _ = r + }() + }() +} + +func foo138() *byte { + type T struct { + x [1]byte + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x[0] +} + +func foo139() *byte { + type T struct { + x struct { + y byte + } + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x.y +} + +// issue 4751 +func foo140() interface{} { + type T struct { + X string + } + type U struct { + X string + T *T + } + t := &T{} // ERROR "&T literal escapes to heap$" + return U{ // ERROR "U literal escapes to heap$" + X: t.X, + T: t, + } +} + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape$" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) + + var buf2 [10]byte // ERROR "moved to heap: buf2$" + F2(buf2[:]) + + var buf3 [10]byte + F3(buf3[:]) + + var buf4 [10]byte // ERROR "moved to heap: buf4$" + F4(buf4[:]) +} + +type Tm struct { + x int +} + +func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +} + +func foo141() { + var f func() + + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + f = t.M // ERROR "foo141 t.M does not escape$" + _ = f +} + +var gf func() + +func foo142() { + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + gf = t.M // ERROR "t.M escapes to heap$" +} + +// issue 3888. +func foo143() { + for i := 0; i < 1000; i++ { + func() { // ERROR "foo143 func literal does not escape$" + for i := 0; i < 1; i++ { + var t Tm + t.M() + } + }() + } +} + +// issue 5773 +// Check that annotations take effect regardless of whether they +// are before or after the use in the source code. + +//go:noescape + +func foo144a(*int) + +func foo144() { + var x int + foo144a(&x) + var y int + foo144b(&y) +} + +//go:noescape + +func foo144b(*int) + +// issue 7313: for loop init should not be treated as "in loop" + +type List struct { + Next *List +} + +func foo145(l List) { // ERROR "foo145 l does not escape$" + var p *List + for p = &l; p.Next != nil; p = p.Next { + } +} + +func foo146(l List) { // ERROR "foo146 l does not escape$" + var p *List + p = &l + for ; p.Next != nil; p = p.Next { + } +} + +func foo147(l List) { // ERROR "foo147 l does not escape$" + var p *List + p = &l + for p.Next != nil { + p = p.Next + } +} + +func foo148(l List) { // ERROR "foo148 l does not escape$" + for p := &l; p.Next != nil; p = p.Next { + } +} + +// related: address of variable should have depth of variable, not of loop + +func foo149(l List) { // ERROR "foo149 l does not escape$" + var p *List + for { + for p = &l; p.Next != nil; p = p.Next { + } + } +} + +// issue 7934: missed ... if element type had no pointers + +var save150 []byte + +func foo150(x ...byte) { // ERROR "leaking param: x$" + save150 = x +} + +func bar150() { + foo150(1, 2, 3) // ERROR "... argument escapes to heap$" +} + +// issue 7931: bad handling of slice of array + +var save151 *int + +func foo151(x *int) { // ERROR "leaking param: x$" + save151 = x +} + +func bar151() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8][0]) +} + +func bar151b() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8][0]) +} + +func bar151c() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8:8][0]) +} + +func bar151d() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8:8][0]) +} + +// issue 8120 + +type U struct { + s *string +} + +func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" + return u.s +} + +type V struct { + s *string +} + +// BAD -- level of leak ought to be 0 +func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" + return &V{u.String()} // ERROR "&V literal escapes to heap$" +} + +func foo152() { + a := "a" // ERROR "moved to heap: a$" + u := U{&a} + v := NewV(u) + println(v) +} + +// issue 8176 - &x in type switch body not marked as escaping + +func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" + switch x := v.(type) { + case int: // ERROR "moved to heap: x$" + return &x + } + panic(0) +} + +// issue 8185 - &result escaping into result + +func f() (x int, y *int) { // ERROR "moved to heap: x$" + y = &x + return +} + +func g() (x interface{}) { // ERROR "moved to heap: x$" + x = &x // ERROR "&x escapes to heap$" + return +} + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" + sink = *x // ERROR "\*x escapes to heap$" +} + +func ptrlitEscape() { + // Both literal and element escape. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" + sink = x // ERROR "x escapes to heap$" +} + +// self-assignments + +type Buffer struct { + arr [64]byte + arrPtr *[64]byte + buf1 []byte + buf2 []byte + str1 string + str2 string +} + +func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" + b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" + b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" + b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" + b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" +} + +func (b *Buffer) bar() { // ERROR "leaking param: b$" + b.buf1 = b.arr[1:2] +} + +func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" + b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" + b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" +} + +func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" + b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" + b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" +} + +func (b *Buffer) bat() { // ERROR "leaking param content: b$" + o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" + o.buf1 = b.buf1[1:2] + sink = o // ERROR "o escapes to heap$" +} + +func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" + *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" + *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" +} + +type StructWithString struct { + p *int + s string +} + +// This is escape analysis false negative. +// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows +// to just x, and thus &i looks escaping. +func fieldFlowTracking() { + var x StructWithString + i := 0 // ERROR "moved to heap: i$" + x.p = &i + sink = x.s // ERROR "x.s escapes to heap$" +} + +// String operations. + +func slicebytetostring0() { + b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + _ = s +} + +func slicebytetostring1() { + b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + s1 := s[0:1] + _ = s1 +} + +func slicebytetostring2() { + b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] // ERROR "moved to heap: s1$" + sink = &s1 // ERROR "&s1 escapes to heap$" +} + +func slicebytetostring3() { + b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] + sink = s1 // ERROR "s1 escapes to heap$" +} + +func addstr0() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + _ = s +} + +func addstr1() { + s0 := "a" + s1 := "b" + s := "c" + s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + _ = s +} + +func addstr2() { + b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + s0 := "a" + s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + _ = s +} + +func addstr3() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" + s2 := s[0:1] + sink = s2 // ERROR "s2 escapes to heap$" +} + +func intstring0() bool { + // string does not escape + x := '0' + s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + return s == "0" +} + +func intstring1() string { + // string does not escape, but the buffer does + x := '0' + s := string(x) // ERROR "string\(x\) escapes to heap$" + return s +} + +func intstring2() { + // string escapes to heap + x := '0' + s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" + sink = &s // ERROR "&s escapes to heap$" +} + +func stringtoslicebyte0() { + s := "foo" + x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + _ = x +} + +func stringtoslicebyte1() []byte { + s := "foo" + return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicebyte2() { + s := "foo" + sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicerune0() { + s := "foo" + x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + _ = x +} + +func stringtoslicerune1() []rune { + s := "foo" + return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func stringtoslicerune2() { + s := "foo" + sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func slicerunetostring0() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" + s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + _ = s +} + +func slicerunetostring1() string { + r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + return string(r) // ERROR "string\(r\) escapes to heap$" +} + +func slicerunetostring2() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + sink = string(r) // ERROR "string\(r\) escapes to heap$" +} + +func makemap0() { + m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m[0] = 0 + m[1]++ + delete(m, 1) + sink = m[0] // ERROR "m\[0\] escapes to heap$" +} + +func makemap1() map[int]int { + return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" +} + +func makemap2() { + m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" + sink = m // ERROR "m escapes to heap$" +} + +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" + return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +} + +func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" + return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +} + +func issue10353() { + x := new(int) // ERROR "new\(int\) escapes to heap$" + issue10353a(x)() +} + +func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" + return func() { // ERROR "func literal escapes to heap$" + println(*x) + } +} + +func issue10353b() { + var f func() + for { + x := new(int) // ERROR "new\(int\) escapes to heap$" + f = func() { // ERROR "func literal escapes to heap$" + println(*x) + } + } + _ = f +} + +func issue11387(x int) func() int { + f := func() int { return x } // ERROR "func literal escapes to heap" + slice1 := []func() int{f} // ERROR "\[\].* does not escape" + slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" + copy(slice2, slice1) + return slice2[0] +} + +func issue12397(x, y int) { // ERROR "moved to heap: y$" + // x does not escape below, because all relevant code is dead. + if false { + gxx = &x + } else { + gxx = &y + } + + if true { + gxx = &y + } else { + gxx = &x + } +} diff --git a/test/oldescape2n.go b/test/oldescape2n.go new file mode 100644 index 00000000000..fb2a9566183 --- /dev/null +++ b/test/oldescape2n.go @@ -0,0 +1,1847 @@ +// errorcheck -0 -N -m -l -newescape=false + +// Copyright 2010 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. + +// Test, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. +// Registerization is disabled too (-N), which should +// have no effect on escape analysis. + +package foo + +import ( + "fmt" + "unsafe" +) + +var gxx *int + +func foo1(x int) { // ERROR "moved to heap: x$" + gxx = &x +} + +func foo2(yy *int) { // ERROR "leaking param: yy$" + gxx = yy +} + +func foo3(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +type T *T + +func foo3b(t T) { // ERROR "leaking param: t$" + *t = t +} + +// xx isn't going anywhere, so use of yy is ok +func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" + xx = yy +} + +// xx isn't going anywhere, so taking address of yy is ok +func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" + xx = &yy +} + +func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" + *xx = yy +} + +func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" + **xx = *yy +} + +func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" + xx = yy + return *xx +} + +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" + xx = yy + return xx +} + +func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" + *xx = *yy +} + +func foo11() int { + x, y := 0, 42 + xx := &x + yy := &y + *xx = *yy + return x +} + +var xxx **int + +func foo12(yyy **int) { // ERROR "leaking param: yyy$" + xxx = yyy +} + +// Must treat yyy as leaking because *yyy leaks, and the escape analysis +// summaries in exported metadata do not distinguish these two cases. +func foo13(yyy **int) { // ERROR "leaking param content: yyy$" + *xxx = *yyy +} + +func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" + **xxx = **yyy +} + +func foo15(yy *int) { // ERROR "moved to heap: yy$" + xxx = &yy +} + +func foo16(yy *int) { // ERROR "leaking param: yy$" + *xxx = yy +} + +func foo17(yy *int) { // ERROR "foo17 yy does not escape$" + **xxx = *yy +} + +func foo18(y int) { // ERROR "moved to heap: y$" + *xxx = &y +} + +func foo19(y int) { + **xxx = y +} + +type Bar struct { + i int + ii *int +} + +func NewBar() *Bar { + return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" + return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" + return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" +} + +func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" + return *(b.ii) +} + +func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return &b.i +} + +func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii +} + +func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.ii +} + +func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" + v := 0 + b.ii = &v + return b.i +} + +func goLeak(b *Bar) { // ERROR "leaking param: b$" + go b.NoLeak() +} + +type Bar2 struct { + i [12]int + ii []int +} + +func NewBar2() *Bar2 { + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" +} + +func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" + return b.i[0] +} + +func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.i[:] +} + +func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii[0:1] +} + +func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" + return b.i +} + +func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" + b.ii = b.i[0:4] +} + +func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" + var buf []int + buf = b.i[0:] + b.ii = buf +} + +func foo21() func() int { + x := 42 + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo21a() func() int { + x := 42 // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo22() int { + x := 42 + return func() int { // ERROR "foo22 func literal does not escape$" + return x + }() +} + +func foo23(x int) func() int { + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo23a(x int) func() int { + f := func() int { // ERROR "func literal escapes to heap$" + return x + } + return f +} + +func foo23b(x int) *(func() int) { + f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" + return &f +} + +func foo23c(x int) func() int { // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo24(x int) int { + return func() int { // ERROR "foo24 func literal does not escape$" + return x + }() +} + +var x *int + +func fooleak(xx *int) int { // ERROR "leaking param: xx$" + x = xx + return *x +} + +func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" + return *x + *xx +} + +func foo31(x int) int { // ERROR "moved to heap: x$" + return fooleak(&x) +} + +func foo32(x int) int { + return foonoleak(&x) +} + +type Foo struct { + xx *int + x int +} + +var F Foo +var pf *Foo + +func (f *Foo) fooleak() { // ERROR "leaking param: f$" + pf = f +} + +func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" + F.x = f.x +} + +func (f *Foo) Leak() { // ERROR "leaking param: f$" + f.fooleak() +} + +func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" + f.foonoleak() +} + +func foo41(x int) { // ERROR "moved to heap: x$" + F.xx = &x +} + +func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo44(yy *int) { // ERROR "leaking param: yy$" + F.xx = yy +} + +func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" + F.x = f.x +} + +// See foo13 above for explanation of why f leaks. +func (f *Foo) foo46() { // ERROR "leaking param content: f$" + F.xx = f.xx +} + +func (f *Foo) foo47() { // ERROR "leaking param: f$" + f.xx = &f.x +} + +var ptrSlice []*int + +func foo50(i *int) { // ERROR "leaking param: i$" + ptrSlice[0] = i +} + +var ptrMap map[*int]*int + +func foo51(i *int) { // ERROR "leaking param: i$" + ptrMap[i] = i +} + +func indaddr1(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *&x +} + +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *(**int)(unsafe.Pointer(&x)) +} + +// From package math: + +func Float32bits(f float32) uint32 { + return *(*uint32)(unsafe.Pointer(&f)) +} + +func Float32frombits(b uint32) float32 { + return *(*float32)(unsafe.Pointer(&b)) +} + +func Float64bits(f float64) uint64 { + return *(*uint64)(unsafe.Pointer(&f)) +} + +func Float64frombits(b uint64) float64 { + return *(*float64)(unsafe.Pointer(&b)) +} + +// contrast with +func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" + return (*uint64)(unsafe.Pointer(&f)) +} + +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" + return (*uint64)(unsafe.Pointer(f)) +} + +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch val := i.(type) { + case *int: + return val + case *int8: + v := int(*val) // ERROR "moved to heap: v$" + return &v + } + return nil +} + +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch j := i; *j + 110 { + case 12: + return j + case 42: + return nil + } + return nil + +} + +// assigning to an array element is like assigning to the array +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + var a [12]*int + a[0] = i + return a[1] +} + +func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" + var a [12]*int + a[0] = i + return nil +} + +// assigning to a struct field is like assigning to the struct +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + type S struct { + a, b *int + } + var s S + s.a = i + return s.b +} + +func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" + type S struct { + a, b *int + } + var s S + s.a = i + return nil +} + +// assigning to a struct field is like assigning to the struct but +// here this subtlety is lost, since s.a counts as an assignment to a +// track-losing dereference. +func foo62(i *int) *int { // ERROR "leaking param: i$" + type S struct { + a, b *int + } + s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s.a = i + return nil // s.b +} + +type M interface { + M() +} + +func foo63(m M) { // ERROR "foo63 m does not escape$" +} + +func foo64(m M) { // ERROR "leaking param: m$" + m.M() +} + +func foo64b(m M) { // ERROR "leaking param: m$" + defer m.M() +} + +type MV int + +func (MV) M() {} + +func foo65() { + var mv MV + foo63(&mv) // ERROR "foo65 &mv does not escape$" +} + +func foo66() { + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) // ERROR "&mv escapes to heap$" +} + +func foo67() { + var mv MV + foo63(mv) // ERROR "foo67 mv does not escape$" +} + +func foo68() { + var mv MV + // escapes but it's an int so irrelevant + foo64(mv) // ERROR "mv escapes to heap$" +} + +func foo69(m M) { // ERROR "leaking param: m$" + foo64(m) +} + +func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" + m = mv1 // ERROR "mv1 escapes to heap$" + foo64(m) +} + +func foo71(x *int) []*int { // ERROR "leaking param: x$" + var y []*int + y = append(y, x) + return y +} + +func foo71a(x int) []*int { // ERROR "moved to heap: x$" + var y []*int + y = append(y, &x) + return y +} + +func foo72() { + var x int + var y [1]*int + y[0] = &x +} + +func foo72aa() [10]*int { + var x int // ERROR "moved to heap: x$" + var y [10]*int + y[0] = &x + return y +} + +func foo72a() { + var y [10]*int + for i := 0; i < 10; i++ { + // escapes its scope + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return +} + +func foo72b() [10]*int { + var y [10]*int + for i := 0; i < 10; i++ { + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return y +} + +// issue 2145 +func foo73() { + s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + println(vv) + }() + } +} + +func foo731() { + s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + vv = 42 + println(vv) + }() + } +} + +func foo74() { + s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + println(vv) + } + defer fn() + } +} + +func foo74a() { + s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + vv += 1 + println(vv) + } + defer fn() + } +} + +// issue 3975 +func foo74b() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" + for i, v := range s { + vv := v + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(vv) + } + } +} + +func foo74c() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" + for i, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(&vv) + } + } +} + +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" + return y +} + +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" + return &x[0] +} + +func foo75(z *int) { // ERROR "foo75 z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +} + +func foo75a(z *int) { // ERROR "foo75a z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +} + +func foo75esc(z *int) { // ERROR "leaking param: z$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" +} + +func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" + var ppi **interface{} // assignments to pointer dereferences lose track + *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" +} + +func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +} + +func foo76(z *int) { // ERROR "z does not escape" + myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" +} + +func foo76a(z *int) { // ERROR "z does not escape" + myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" +} + +func foo76b() { + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" +} + +func foo76c() { + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" +} + +func foo76d() { + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" +} + +func foo76e() { + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" +} + +func foo76f() { + for { + // TODO: This one really only escapes its scope, but we don't distinguish yet. + defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo76g() { + for { + defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" + myprint(nil, z...) // z does not escape +} + +func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" + myprint1(nil, z...) +} + +func foo77b(z []interface{}) { // ERROR "leaking param: z$" + var ppi **interface{} + *ppi = myprint1(nil, z...) +} + +func foo77c(z []interface{}) { // ERROR "leaking param: z$" + sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" +} + +func dotdotdot() { + i := 0 + myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + + j := 0 + myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" +} + +func foo78(z int) *int { // ERROR "moved to heap: z$" + return &z +} + +func foo78a(z int) *int { // ERROR "moved to heap: z$" + y := &z + x := &y + return *x // really return y +} + +func foo79() *int { + return new(int) // ERROR "new\(int\) escapes to heap$" +} + +func foo80() *int { + var z *int + for { + // Really just escapes its scope but we don't distinguish + z = new(int) // ERROR "new\(int\) escapes to heap$" + } + _ = z + return nil +} + +func foo81() *int { + for { + z := new(int) // ERROR "foo81 new\(int\) does not escape$" + _ = z + } + return nil +} + +func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" + +func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" + +func foo82() { + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + go noop(tee(&z)) + go noop(&x, &y) + for { + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + defer noop(tee(&u)) + defer noop(&v, &w) + } +} + +type Fooer interface { + Foo() +} + +type LimitedFooer struct { + Fooer + N int64 +} + +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" +} + +func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" + return [2]*int{x, nil} +} + +// does not leak c +func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" + for v := range c { + return v + } + return nil +} + +// does not leak m +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" + 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 "foo95 m does not escape$" "leaking param: x$" + m[x] = x +} + +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + return m[0] +} + +// does leak m +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[0] +} + +// does not leak m +func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" + return m[0] +} + +// does leak m +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[:] +} + +// does not leak m +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + for _, v := range m { + return v + } + return nil +} + +// does leak m +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + for _, v := range m { + return v + } + return nil +} + +// does not leak m +func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" + for i := range m { // ERROR "moved to heap: i$" + return &i + } + return nil +} + +// does leak x +func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" + m[0] = x +} + +// does not leak x +func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" + m[0] = x +} + +var y []*int + +// does not leak x but does leak content +func foo104(x []*int) { // ERROR "leaking param content: x" + copy(y, x) +} + +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" + _ = append(y, x...) +} + +// does leak x +func foo106(x *int) { // ERROR "leaking param: x$" + _ = append(y, x) +} + +func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo109(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + for k, _ := range m { + return k + } + return nil +} + +func foo110(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" + return m[nil] +} + +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" + m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + return m[0] +} + +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := [1]*int{x} + return m[0] +} + +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := Bar{ii: x} + return m.ii +} + +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" + return m.ii +} + +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) +} + +func foo116(b bool) *int { + if b { + x := 1 // ERROR "moved to heap: x$" + return &x + } else { + y := 1 // ERROR "moved to heap: y$" + return &y + } + return nil +} + +func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) // ERROR "&x escapes to heap$" +} + +func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) +} + +func external(*int) + +func foo119(x *int) { // ERROR "leaking param: x$" + external(x) +} + +func foo120() { + // formerly exponential time analysis +L1: +L2: +L3: +L4: +L5: +L6: +L7: +L8: +L9: +L10: +L11: +L12: +L13: +L14: +L15: +L16: +L17: +L18: +L19: +L20: +L21: +L22: +L23: +L24: +L25: +L26: +L27: +L28: +L29: +L30: +L31: +L32: +L33: +L34: +L35: +L36: +L37: +L38: +L39: +L40: +L41: +L42: +L43: +L44: +L45: +L46: +L47: +L48: +L49: +L50: +L51: +L52: +L53: +L54: +L55: +L56: +L57: +L58: +L59: +L60: +L61: +L62: +L63: +L64: +L65: +L66: +L67: +L68: +L69: +L70: +L71: +L72: +L73: +L74: +L75: +L76: +L77: +L78: +L79: +L80: +L81: +L82: +L83: +L84: +L85: +L86: +L87: +L88: +L89: +L90: +L91: +L92: +L93: +L94: +L95: +L96: +L97: +L98: +L99: +L100: + // use the labels to silence compiler errors + goto L1 + goto L2 + goto L3 + goto L4 + goto L5 + goto L6 + goto L7 + goto L8 + goto L9 + goto L10 + goto L11 + goto L12 + goto L13 + goto L14 + goto L15 + goto L16 + goto L17 + goto L18 + goto L19 + goto L20 + goto L21 + goto L22 + goto L23 + goto L24 + goto L25 + goto L26 + goto L27 + goto L28 + goto L29 + goto L30 + goto L31 + goto L32 + goto L33 + goto L34 + goto L35 + goto L36 + goto L37 + goto L38 + goto L39 + goto L40 + goto L41 + goto L42 + goto L43 + goto L44 + goto L45 + goto L46 + goto L47 + goto L48 + goto L49 + goto L50 + goto L51 + goto L52 + goto L53 + goto L54 + goto L55 + goto L56 + goto L57 + goto L58 + goto L59 + goto L60 + goto L61 + goto L62 + goto L63 + goto L64 + goto L65 + goto L66 + goto L67 + goto L68 + goto L69 + goto L70 + goto L71 + goto L72 + goto L73 + goto L74 + goto L75 + goto L76 + goto L77 + goto L78 + goto L79 + goto L80 + goto L81 + goto L82 + goto L83 + goto L84 + goto L85 + goto L86 + goto L87 + goto L88 + goto L89 + goto L90 + goto L91 + goto L92 + goto L93 + goto L94 + goto L95 + goto L96 + goto L97 + goto L98 + goto L99 + goto L100 +} + +func foo121() { + for i := 0; i < 10; i++ { + defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + go myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// same as foo121 but check across import +func foo121b() { + for i := 0; i < 10; i++ { + defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// a harmless forward jump +func foo122() { + var i *int + + goto L1 +L1: + i = new(int) // ERROR "foo122 new\(int\) does not escape$" + _ = i +} + +// a backward jump, increases loopdepth +func foo123() { + var i *int + +L1: + i = new(int) // ERROR "new\(int\) escapes to heap$" + + goto L1 + _ = i +} + +func foo124(x **int) { // ERROR "foo124 x does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo124 func literal does not escape$" + *x = p + }() +} + +func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo125 func literal does not escape$" + ch <- p + }() +} + +func foo126() { + var px *int // loopdepth 0 + for { + // loopdepth 1 + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo126 func literal does not escape$" + px = &i + }() + } + _ = px +} + +var px *int + +func foo127() { + var i int // ERROR "moved to heap: i$" + p := &i + q := p + px = q +} + +func foo128() { + var i int + p := &i + q := p + _ = q +} + +func foo129() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo129 func literal does not escape$" + q := p + func() { // ERROR "foo129.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo130() { + for { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo130 func literal does not escape$" + px = &i + }() + } +} + +func foo131() { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo131 func literal does not escape$" + px = &i + }() +} + +func foo132() { + var i int // ERROR "moved to heap: i$" + go func() { // ERROR "func literal escapes to heap$" + px = &i + }() +} + +func foo133() { + var i int // ERROR "moved to heap: i$" + defer func() { // ERROR "foo133 func literal does not escape$" + px = &i + }() +} + +func foo134() { + var i int + p := &i + func() { // ERROR "foo134 func literal does not escape$" + q := p + func() { // ERROR "foo134.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo135() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo135.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo136() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo136.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo137() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo137 func literal does not escape$" + q := p + go func() { // ERROR "func literal escapes to heap$" + r := q + _ = r + }() + }() +} + +func foo138() *byte { + type T struct { + x [1]byte + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x[0] +} + +func foo139() *byte { + type T struct { + x struct { + y byte + } + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x.y +} + +// issue 4751 +func foo140() interface{} { + type T struct { + X string + } + type U struct { + X string + T *T + } + t := &T{} // ERROR "&T literal escapes to heap$" + return U{ // ERROR "U literal escapes to heap$" + X: t.X, + T: t, + } +} + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape$" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) + + var buf2 [10]byte // ERROR "moved to heap: buf2$" + F2(buf2[:]) + + var buf3 [10]byte + F3(buf3[:]) + + var buf4 [10]byte // ERROR "moved to heap: buf4$" + F4(buf4[:]) +} + +type Tm struct { + x int +} + +func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +} + +func foo141() { + var f func() + + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + f = t.M // ERROR "foo141 t.M does not escape$" + _ = f +} + +var gf func() + +func foo142() { + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + gf = t.M // ERROR "t.M escapes to heap$" +} + +// issue 3888. +func foo143() { + for i := 0; i < 1000; i++ { + func() { // ERROR "foo143 func literal does not escape$" + for i := 0; i < 1; i++ { + var t Tm + t.M() + } + }() + } +} + +// issue 5773 +// Check that annotations take effect regardless of whether they +// are before or after the use in the source code. + +//go:noescape + +func foo144a(*int) + +func foo144() { + var x int + foo144a(&x) + var y int + foo144b(&y) +} + +//go:noescape + +func foo144b(*int) + +// issue 7313: for loop init should not be treated as "in loop" + +type List struct { + Next *List +} + +func foo145(l List) { // ERROR "foo145 l does not escape$" + var p *List + for p = &l; p.Next != nil; p = p.Next { + } +} + +func foo146(l List) { // ERROR "foo146 l does not escape$" + var p *List + p = &l + for ; p.Next != nil; p = p.Next { + } +} + +func foo147(l List) { // ERROR "foo147 l does not escape$" + var p *List + p = &l + for p.Next != nil { + p = p.Next + } +} + +func foo148(l List) { // ERROR "foo148 l does not escape$" + for p := &l; p.Next != nil; p = p.Next { + } +} + +// related: address of variable should have depth of variable, not of loop + +func foo149(l List) { // ERROR "foo149 l does not escape$" + var p *List + for { + for p = &l; p.Next != nil; p = p.Next { + } + } +} + +// issue 7934: missed ... if element type had no pointers + +var save150 []byte + +func foo150(x ...byte) { // ERROR "leaking param: x$" + save150 = x +} + +func bar150() { + foo150(1, 2, 3) // ERROR "... argument escapes to heap$" +} + +// issue 7931: bad handling of slice of array + +var save151 *int + +func foo151(x *int) { // ERROR "leaking param: x$" + save151 = x +} + +func bar151() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8][0]) +} + +func bar151b() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8][0]) +} + +func bar151c() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8:8][0]) +} + +func bar151d() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8:8][0]) +} + +// issue 8120 + +type U struct { + s *string +} + +func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" + return u.s +} + +type V struct { + s *string +} + +// BAD -- level of leak ought to be 0 +func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" + return &V{u.String()} // ERROR "&V literal escapes to heap$" +} + +func foo152() { + a := "a" // ERROR "moved to heap: a$" + u := U{&a} + v := NewV(u) + println(v) +} + +// issue 8176 - &x in type switch body not marked as escaping + +func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" + switch x := v.(type) { + case int: // ERROR "moved to heap: x$" + return &x + } + panic(0) +} + +// issue 8185 - &result escaping into result + +func f() (x int, y *int) { // ERROR "moved to heap: x$" + y = &x + return +} + +func g() (x interface{}) { // ERROR "moved to heap: x$" + x = &x // ERROR "&x escapes to heap$" + return +} + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" + sink = *x // ERROR "\*x escapes to heap$" +} + +func ptrlitEscape() { + // Both literal and element escape. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" + sink = x // ERROR "x escapes to heap$" +} + +// self-assignments + +type Buffer struct { + arr [64]byte + arrPtr *[64]byte + buf1 []byte + buf2 []byte + str1 string + str2 string +} + +func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" + b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" + b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" + b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" + b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" +} + +func (b *Buffer) bar() { // ERROR "leaking param: b$" + b.buf1 = b.arr[1:2] +} + +func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" + b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" + b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" +} + +func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" + b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" + b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" +} + +func (b *Buffer) bat() { // ERROR "leaking param content: b$" + o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" + o.buf1 = b.buf1[1:2] + sink = o // ERROR "o escapes to heap$" +} + +func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" + *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" + *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" +} + +type StructWithString struct { + p *int + s string +} + +// This is escape analysis false negative. +// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows +// to just x, and thus &i looks escaping. +func fieldFlowTracking() { + var x StructWithString + i := 0 // ERROR "moved to heap: i$" + x.p = &i + sink = x.s // ERROR "x.s escapes to heap$" +} + +// String operations. + +func slicebytetostring0() { + b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + _ = s +} + +func slicebytetostring1() { + b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + s1 := s[0:1] + _ = s1 +} + +func slicebytetostring2() { + b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] // ERROR "moved to heap: s1$" + sink = &s1 // ERROR "&s1 escapes to heap$" +} + +func slicebytetostring3() { + b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] + sink = s1 // ERROR "s1 escapes to heap$" +} + +func addstr0() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + _ = s +} + +func addstr1() { + s0 := "a" + s1 := "b" + s := "c" + s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + _ = s +} + +func addstr2() { + b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + s0 := "a" + s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + _ = s +} + +func addstr3() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" + s2 := s[0:1] + sink = s2 // ERROR "s2 escapes to heap$" +} + +func intstring0() bool { + // string does not escape + x := '0' + s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + return s == "0" +} + +func intstring1() string { + // string does not escape, but the buffer does + x := '0' + s := string(x) // ERROR "string\(x\) escapes to heap$" + return s +} + +func intstring2() { + // string escapes to heap + x := '0' + s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" + sink = &s // ERROR "&s escapes to heap$" +} + +func stringtoslicebyte0() { + s := "foo" + x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + _ = x +} + +func stringtoslicebyte1() []byte { + s := "foo" + return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicebyte2() { + s := "foo" + sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicerune0() { + s := "foo" + x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + _ = x +} + +func stringtoslicerune1() []rune { + s := "foo" + return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func stringtoslicerune2() { + s := "foo" + sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func slicerunetostring0() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" + s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + _ = s +} + +func slicerunetostring1() string { + r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + return string(r) // ERROR "string\(r\) escapes to heap$" +} + +func slicerunetostring2() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + sink = string(r) // ERROR "string\(r\) escapes to heap$" +} + +func makemap0() { + m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m[0] = 0 + m[1]++ + delete(m, 1) + sink = m[0] // ERROR "m\[0\] escapes to heap$" +} + +func makemap1() map[int]int { + return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" +} + +func makemap2() { + m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" + sink = m // ERROR "m escapes to heap$" +} + +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" + return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +} + +func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" + return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +} + +func issue10353() { + x := new(int) // ERROR "new\(int\) escapes to heap$" + issue10353a(x)() +} + +func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" + return func() { // ERROR "func literal escapes to heap$" + println(*x) + } +} + +func issue10353b() { + var f func() + for { + x := new(int) // ERROR "new\(int\) escapes to heap$" + f = func() { // ERROR "func literal escapes to heap$" + println(*x) + } + } + _ = f +} + +func issue11387(x int) func() int { + f := func() int { return x } // ERROR "func literal escapes to heap" + slice1 := []func() int{f} // ERROR "\[\].* does not escape" + slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" + copy(slice2, slice1) + return slice2[0] +} + +func issue12397(x, y int) { // ERROR "moved to heap: y$" + // x does not escape below, because all relevant code is dead. + if false { + gxx = &x + } else { + gxx = &y + } + + if true { + gxx = &y + } else { + gxx = &x + } +} diff --git a/test/oldescape5.go b/test/oldescape5.go new file mode 100644 index 00000000000..53d0ff801d5 --- /dev/null +++ b/test/oldescape5.go @@ -0,0 +1,247 @@ +// errorcheck -0 -m -l -newescape=false + +// 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. + +// Test, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. + +package foo + +import "runtime" + +func noleak(p *int) int { // ERROR "p does not escape" + return *p +} + +func leaktoret(p *int) *int { // ERROR "leaking param: p to result" + return p +} + +func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2" + return p, p +} + +func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3" + return p, q +} + +func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" + return leaktoret22(q, p) +} + +func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" + r, s := leaktoret22(q, p) + return r, s +} + +func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" + r, s = leaktoret22(q, p) + return +} + +func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" + r, s = leaktoret22(q, p) + return r, s +} + +func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" + rr, ss := leaktoret22(q, p) + return rr, ss +} + +var gp *int + +func leaktosink(p *int) *int { // ERROR "leaking param: p" + gp = p + return p +} + +func f1() { + var x int + p := noleak(&x) + _ = p +} + +func f2() { + var x int + p := leaktoret(&x) + _ = p +} + +func f3() { + var x int // ERROR "moved to heap: x" + p := leaktoret(&x) + gp = p +} + +func f4() { + var x int // ERROR "moved to heap: x" + p, q := leaktoret2(&x) + gp = p + gp = q +} + +func f5() { + var x int + leaktoret22(leaktoret2(&x)) +} + +func f6() { + var x int // ERROR "moved to heap: x" + px1, px2 := leaktoret22(leaktoret2(&x)) + gp = px1 + _ = px2 +} + +type T struct{ x int } + +func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result" + t.x += u + return t, true +} + +func f7() *T { + r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap" + return r +} + +func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" + return leakrecursive2(q, p) +} + +func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" + if *p > *q { + return leakrecursive1(q, p) + } + // without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges. + return p, q +} + +var global interface{} + +type T1 struct { + X *int +} + +type T2 struct { + Y *T1 +} + +func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p" + if p == nil { + k = T2{} + return + } + + // should make p leak always + global = p // ERROR "p escapes to heap" + return T2{p} +} + +func f9() { + var j T1 // ERROR "moved to heap: j" + f8(&j) +} + +func f10() { + // These don't escape but are too big for the stack + var x [1 << 30]byte // ERROR "moved to heap: x" + var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap" + _ = x[0] + y[0] +} + +// Test for issue 19687 (passing to unnamed parameters does not escape). +func f11(**int) { +} +func f12(_ **int) { +} +func f13() { + var x *int + f11(&x) + f12(&x) + runtime.KeepAlive(&x) // ERROR "&x does not escape" +} + +// Test for issue 24305 (passing to unnamed receivers does not escape). +type U int + +func (*U) M() {} +func (_ *U) N() {} + +func _() { + var u U + u.M() + u.N() +} + +// Issue 24730: taking address in a loop causes unnecessary escape +type T24730 struct { + x [64]byte +} + +func (t *T24730) g() { // ERROR "t does not escape" + y := t.x[:] + for i := range t.x[:] { + y = t.x[:] + y[i] = 1 + } + + var z *byte + for i := range t.x[:] { + z = &t.x[i] + *z = 2 + } +} + +// Issue 15730: copy causes unnecessary escape + +var sink []byte +var sink2 []int +var sink3 []*int + +func f15730a(args ...interface{}) { // ERROR "args does not escape" + for _, arg := range args { + switch a := arg.(type) { + case string: + copy(sink, a) + } + } +} + +func f15730b(args ...interface{}) { // ERROR "args does not escape" + for _, arg := range args { + switch a := arg.(type) { + case []int: + copy(sink2, a) + } + } +} + +func f15730c(args ...interface{}) { // ERROR "leaking param content: args" + for _, arg := range args { + switch a := arg.(type) { + case []*int: + // copy pointerful data should cause escape + copy(sink3, a) + } + } +} + +// Issue 29000: unnamed parameter is not handled correctly + +var sink4 interface{} +var alwaysFalse = false + +func f29000(_ int, x interface{}) { // ERROR "leaking param: x" + sink4 = x + if alwaysFalse { + g29000() + } +} + +func g29000() { + x := 1 + f29000(2, x) // ERROR "x escapes to heap" +} diff --git a/test/oldescape_calls.go b/test/oldescape_calls.go new file mode 100644 index 00000000000..715e8321130 --- /dev/null +++ b/test/oldescape_calls.go @@ -0,0 +1,54 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis for function parameters. + +// In this test almost everything is BAD except the simplest cases +// where input directly flows to output. + +package foo + +func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$" + return buf +} + +func g(*byte) string + +func h(e int) { + var x [32]byte // ERROR "moved to heap: x$" + g(&f(x[:])[0]) +} + +type Node struct { + s string + left, right *Node +} + +func walk(np **Node) int { // ERROR "leaking param content: np" + n := *np + w := len(n.s) + if n == nil { + return 0 + } + wl := walk(&n.left) + wr := walk(&n.right) + if wl < wr { + n.left, n.right = n.right, n.left + wl, wr = wr, wl + } + *np = n + return w + wl + wr +} + +// Test for bug where func var f used prototype's escape analysis results. +func prototype(xyz []string) {} // ERROR "prototype xyz does not escape" +func bar() { + var got [][]string + f := prototype + f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape" + s := "string" + f([]string{s}) // ERROR "\[\]string literal escapes to heap" +} diff --git a/test/oldescape_closure.go b/test/oldescape_closure.go new file mode 100644 index 00000000000..386605dfcdd --- /dev/null +++ b/test/oldescape_closure.go @@ -0,0 +1,173 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis for closure arguments. + +package escape + +var sink interface{} + +func ClosureCallArgs0() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) +} + +func ClosureCallArgs1() { + x := 0 // ERROR "moved to heap: x" + for { + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) + } +} + +func ClosureCallArgs2() { + for { + // BAD: x should not escape here + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs3() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + sink = p // ERROR "p escapes to heap" + }(&x) +} + +func ClosureCallArgs4() { + // BAD: x should not leak here + x := 0 // ERROR "moved to heap: x" + _ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + return p + }(&x) +} + +func ClosureCallArgs5() { + x := 0 // ERROR "moved to heap: x" + sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" + return p + }(&x) +} + +func ClosureCallArgs6() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" + sink = &p // ERROR "&p escapes to heap" + }(&x) +} + +func ClosureCallArgs7() { + var pp *int + for { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + pp = p + }(&x) + } + _ = pp +} + +func ClosureCallArgs8() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) +} + +func ClosureCallArgs9() { + // BAD: x should not leak + x := 0 // ERROR "moved to heap: x" + for { + defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs10() { + for { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs11() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + sink = p // ERROR "p escapes to heap" + }(&x) +} + +func ClosureCallArgs12() { + // BAD: x should not leak + x := 0 // ERROR "moved to heap: x" + defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + return p + }(&x) +} + +func ClosureCallArgs13() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" + sink = &p // ERROR "&p escapes to heap" + }(&x) +} + +func ClosureCallArgs14() { + x := 0 // ERROR "moved to heap: x" + // BAD: &x should not escape here + p := &x // ERROR "moved to heap: p" + _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" + return *p + // BAD: p should not escape here + }(&p) +} + +func ClosureCallArgs15() { + x := 0 // ERROR "moved to heap: x" + p := &x // ERROR "moved to heap: p" + sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" + return *p + // BAD: p should not escape here + }(&p) +} + +func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + return ClosureLeak1a(t) // ERROR "ClosureLeak1 ... argument does not escape" +} + +// See #14409 -- returning part of captured var leaks it. +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return func() string { // ERROR "ClosureLeak1a func literal does not escape" + return a[0] + }() +} + +func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" + return c +} +func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" + return a[0] + }) +} +func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" + return f() +} diff --git a/test/oldescape_field.go b/test/oldescape_field.go new file mode 100644 index 00000000000..e4213aaf590 --- /dev/null +++ b/test/oldescape_field.go @@ -0,0 +1,174 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis with respect to field assignments. + +package escape + +var sink interface{} + +type X struct { + p1 *int + p2 *int + a [2]*int +} + +type Y struct { + x X +} + +func field0() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + sink = x.p1 // ERROR "x\.p1 escapes to heap" +} + +func field1() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field3() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + sink = x // ERROR "x escapes to heap" +} + +func field4() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + sink = x // ERROR "x escapes to heap" +} + +func field5() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape here + x.a[0] = &i + sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap" +} + +// BAD: we are not leaking param x, only x.p2 +func field6(x *X) { // ERROR "leaking param content: x$" + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field6a() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + field6(&x) +} + +func field7() { + i := 0 + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + _ = y1.x.p1 +} + +func field8() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap" +} + +func field9() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x // ERROR "y1\.x escapes to heap" +} + +func field10() { + i := 0 // ERROR "moved to heap: i$" + var y Y + // BAD: &i should not escape + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap" +} + +func field11() { + i := 0 // ERROR "moved to heap: i$" + x := X{p1: &i} + sink = x.p1 // ERROR "x\.p1 escapes to heap" +} + +func field12() { + i := 0 // ERROR "moved to heap: i$" + // BAD: &i should not escape + x := X{p1: &i} + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field13() { + i := 0 // ERROR "moved to heap: i$" + x := &X{p1: &i} // ERROR "field13 &X literal does not escape$" + sink = x.p1 // ERROR "x\.p1 escapes to heap" +} + +func field14() { + i := 0 // ERROR "moved to heap: i$" + // BAD: &i should not escape + x := &X{p1: &i} // ERROR "field14 &X literal does not escape$" + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field15() { + i := 0 // ERROR "moved to heap: i$" + x := &X{p1: &i} // ERROR "&X literal escapes to heap$" + sink = x // ERROR "x escapes to heap" +} + +func field16() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + var iface interface{} = x // ERROR "x escapes to heap" + x1 := iface.(X) + sink = x1.p2 // ERROR "x1\.p2 escapes to heap" +} + +func field17() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + var iface interface{} = x // ERROR "x escapes to heap" + x1 := iface.(X) + sink = x1.p1 // ERROR "x1\.p1 escapes to heap" +} + +func field18() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + var iface interface{} = x // ERROR "x escapes to heap" + y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized. + sink = y // ERROR "y escapes to heap" +} diff --git a/test/oldescape_iface.go b/test/oldescape_iface.go new file mode 100644 index 00000000000..88502df99b3 --- /dev/null +++ b/test/oldescape_iface.go @@ -0,0 +1,261 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis for interface conversions. + +package escape + +var sink interface{} + +type M interface { + M() +} + +func mescapes(m M) { // ERROR "leaking param: m" + sink = m // ERROR "m escapes to heap" +} + +func mdoesnotescape(m M) { // ERROR "m does not escape" +} + +// Tests for type stored directly in iface and with value receiver method. +type M0 struct { + p *int +} + +func (M0) M() { +} + +func efaceEscape0() { + { + i := 0 + v := M0{&i} + var x M = v // ERROR "v does not escape" + _ = x + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + var x M = v // ERROR "v escapes to heap" + sink = x // ERROR "x escapes to heap" + } + { + i := 0 + v := M0{&i} + var x M = v // ERROR "v does not escape" + v1 := x.(M0) + _ = v1 + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + v1 := x.(M0) + sink = v1 // ERROR "v1 escapes to heap" + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + x.M() + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := M0{&i} + var x M = v // ERROR "v does not escape" + mdoesnotescape(x) + } +} + +// Tests for type stored indirectly in iface and with value receiver method. +type M1 struct { + p *int + x int +} + +func (M1) M() { +} + +func efaceEscape1() { + { + i := 0 + v := M1{&i, 0} + var x M = v // ERROR "v does not escape" + _ = x + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + var x M = v // ERROR "v escapes to heap" + sink = x // ERROR "x escapes to heap" + } + { + i := 0 + v := M1{&i, 0} + var x M = v // ERROR "v does not escape" + v1 := x.(M1) + _ = v1 + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + v1 := x.(M1) + sink = v1 // ERROR "v1 escapes to heap" + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + x.M() + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := M1{&i, 0} + var x M = v // ERROR "v does not escape" + mdoesnotescape(x) + } +} + +// Tests for type stored directly in iface and with pointer receiver method. +type M2 struct { + p *int +} + +func (*M2) M() { +} + +func efaceEscape2() { + { + i := 0 + v := &M2{&i} // ERROR "&M2 literal does not escape" + var x M = v // ERROR "v does not escape" + _ = x + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal escapes to heap" + var x M = v // ERROR "v escapes to heap" + sink = x // ERROR "x escapes to heap" + } + { + i := 0 + v := &M2{&i} // ERROR "&M2 literal does not escape" + var x M = v // ERROR "v does not escape" + v1 := x.(*M2) + _ = v1 + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal escapes to heap" + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + v1 := x.(*M2) + sink = v1 // ERROR "v1 escapes to heap" + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal does not escape" + // BAD: v does not escape to heap here + var x M = v // ERROR "v does not escape" + v1 := x.(*M2) + sink = *v1 // ERROR "v1 escapes to heap" + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal does not escape" + // BAD: v does not escape to heap here + var x M = v // ERROR "v does not escape" + v1, ok := x.(*M2) + sink = *v1 // ERROR "v1 escapes to heap" + _ = ok + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal escapes to heap" + // BAD: v does not escape to heap here + var x M = v // ERROR "v escapes to heap" + x.M() + } + { + i := 0 // ERROR "moved to heap: i" + v := &M2{&i} // ERROR "&M2 literal escapes to heap" + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := &M2{&i} // ERROR "&M2 literal does not escape" + var x M = v // ERROR "v does not escape" + mdoesnotescape(x) + } +} + +type T1 struct { + p *int +} + +type T2 struct { + T1 T1 +} + +func dotTypeEscape() *T2 { // #11931 + var x interface{} + x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1 literal does not escape" + return &T2{ + T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap" + } +} + +func dotTypeEscape2() { // #13805, #15796 + { + i := 0 + j := 0 + var v int + var ok bool + var x interface{} = i // ERROR "i does not escape" + var y interface{} = j // ERROR "j does not escape" + + *(&v) = x.(int) + *(&v), *(&ok) = y.(int) + } + { + i := 0 + j := 0 + var ok bool + var x interface{} = i // ERROR "i does not escape" + var y interface{} = j // ERROR "j does not escape" + + sink = x.(int) // ERROR "x.\(int\) escapes to heap" + sink, *(&ok) = y.(int) + } + { + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" + var ok bool + var x interface{} = &i // ERROR "&i escapes to heap" + var y interface{} = &j // ERROR "&j escapes to heap" + + sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" + sink, *(&ok) = y.(*int) + } +} diff --git a/test/oldescape_linkname.dir/linkname1.go b/test/oldescape_linkname.dir/linkname1.go new file mode 100644 index 00000000000..9c61522fcc9 --- /dev/null +++ b/test/oldescape_linkname.dir/linkname1.go @@ -0,0 +1,10 @@ +package x + +func indexByte(xs []byte, b byte) int { // ERROR "indexByte xs does not escape" + for i, x := range xs { + if x == b { + return i + } + } + return -1 +} diff --git a/test/oldescape_linkname.dir/linkname2.go b/test/oldescape_linkname.dir/linkname2.go new file mode 100644 index 00000000000..5df4f50ff2c --- /dev/null +++ b/test/oldescape_linkname.dir/linkname2.go @@ -0,0 +1,13 @@ +package y + +import _ "unsafe" + +//go:linkname byteIndex linkname1.indexByte +func byteIndex(xs []byte, b byte) int + +func ContainsSlash(data []byte) bool { // ERROR "leaking param: data" "can inline ContainsSlash" + if byteIndex(data, '/') != -1 { + return true + } + return false +} diff --git a/test/oldescape_linkname.dir/linkname3.go b/test/oldescape_linkname.dir/linkname3.go new file mode 100644 index 00000000000..cbbd3a10ba2 --- /dev/null +++ b/test/oldescape_linkname.dir/linkname3.go @@ -0,0 +1,11 @@ +package main + +import _ "./linkname1" +import "./linkname2" + +func main() { // ERROR "can inline main" + str := "hello/world" + bs := []byte(str) // ERROR "\(\[\]byte\)\(str\) escapes to heap" + if y.ContainsSlash(bs) { // ERROR "inlining call to y.ContainsSlash" + } +} diff --git a/test/oldescape_linkname.go b/test/oldescape_linkname.go new file mode 100644 index 00000000000..f99df1bb800 --- /dev/null +++ b/test/oldescape_linkname.go @@ -0,0 +1,15 @@ +// errorcheckandrundir -0 -m -l=4 -newescape=false + +// Copyright 2010 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. + +// Tests that linknames are included in export data (issue 18167). +package ignored + +/* +Without CL 33911, this test would fail with the following error: + +main.main: relocation target linkname2.byteIndex not defined +main.main: undefined: "linkname2.byteIndex" +*/ diff --git a/test/oldescape_param.go b/test/oldescape_param.go new file mode 100644 index 00000000000..3a3eee2a5bd --- /dev/null +++ b/test/oldescape_param.go @@ -0,0 +1,441 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis for function parameters. + +// In this test almost everything is BAD except the simplest cases +// where input directly flows to output. + +package escape + +func zero() int { return 0 } + +var sink interface{} + +// in -> out +func param0(p *int) *int { // ERROR "leaking param: p to result ~r1" + return p +} + +func caller0a() { + i := 0 + _ = param0(&i) +} + +func caller0b() { + i := 0 // ERROR "moved to heap: i$" + sink = param0(&i) // ERROR "param0\(&i\) escapes to heap" +} + +// in, in -> out, out +func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2" "leaking param: p2 to result ~r3" + return p1, p2 +} + +func caller1() { + i := 0 // ERROR "moved to heap: i$" + j := 0 + sink, _ = param1(&i, &j) +} + +// in -> other in +func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does not escape$" + *p2 = p1 +} + +func caller2a() { + i := 0 // ERROR "moved to heap: i$" + var p *int + param2(&i, &p) + _ = p +} + +func caller2b() { + i := 0 // ERROR "moved to heap: i$" + var p *int + param2(&i, &p) + sink = p // ERROR "p escapes to heap$" +} + +func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape" + p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]" +} + +func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p" + // Function call inside index disables self-assignment case to trigger. + p.pairs[zero()] = p.pairs[1] + p.pairs[zero()+1] = p.pairs[1] +} + +type PairOfPairs struct { + pairs [2]*Pair +} + +type BoxedPair struct { + pair *Pair +} + +type WrappedPair struct { + pair Pair +} + +func leakParam(x interface{}) { // ERROR "leaking param: x" + sink = x +} + +func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + sink = box.pair.p2 // ERROR "box.pair.p2 escapes to heap" +} + +func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + sink = box.pair // ERROR "box.pair escapes to heap" +} + +func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + leakParam(box.pair.p2) // ERROR "box.pair.p2 escapes to heap" +} + +func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + leakParam(box.pair) // ERROR "box.pair escapes to heap" +} + +func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" + box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2" + leakParam(box2.pair.p2) // ERROR "box2.pair.p2 escapes to heap" +} + +func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" + box1.pair.p1 = box2.pair.p1 +} + +func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" + p1.pairs[0] = p2.pairs[1] +} + +func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" + p1.pairs[0].p1 = p2.pairs[1].p1 +} + +func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" +} + +func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape" + w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2" +} + +// in -> in +type Pair struct { + p1 *int + p2 *int +} + +func param3(p *Pair) { // ERROR "param3 p does not escape" + p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2" +} + +func caller3a() { + i := 0 + j := 0 + p := Pair{&i, &j} + param3(&p) + _ = p +} + +func caller3b() { + i := 0 // ERROR "moved to heap: i$" + j := 0 // ERROR "moved to heap: j$" + p := Pair{&i, &j} + param3(&p) + sink = p // ERROR "p escapes to heap$" +} + +// in -> rcvr +func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" "leaking param: i$" + p.p1 = i +} + +func caller4a() { + i := 0 // ERROR "moved to heap: i$" + p := Pair{} + p.param4(&i) + _ = p +} + +func caller4b() { + i := 0 // ERROR "moved to heap: i$" + p := Pair{} + p.param4(&i) + sink = p // ERROR "p escapes to heap$" +} + +// in -> heap +func param5(i *int) { // ERROR "leaking param: i$" + sink = i // ERROR "i escapes to heap$" +} + +func caller5() { + i := 0 // ERROR "moved to heap: i$" + param5(&i) +} + +// *in -> heap +func param6(i ***int) { // ERROR "leaking param content: i$" + sink = *i // ERROR "\*i escapes to heap$" +} + +func caller6a() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param6(&p2) +} + +// **in -> heap +func param7(i ***int) { // ERROR "leaking param content: i$" + sink = **i // ERROR "\* \(\*i\) escapes to heap" +} + +func caller7() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param7(&p2) +} + +// **in -> heap +func param8(i **int) { // ERROR "param8 i does not escape$" + sink = **i // ERROR "\* \(\*i\) escapes to heap" +} + +func caller8() { + i := 0 + p := &i + param8(&p) +} + +// *in -> out +func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1" + return *p +} + +func caller9a() { + i := 0 + p := &i + p2 := &p + _ = param9(&p2) +} + +func caller9b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + sink = param9(&p2) // ERROR "param9\(&p2\) escapes to heap" +} + +// **in -> out +func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2" + return **p +} + +func caller10a() { + i := 0 + p := &i + p2 := &p + _ = param10(&p2) +} + +func caller10b() { + i := 0 // ERROR "moved to heap: i$" + p := &i + p2 := &p + sink = param10(&p2) // ERROR "param10\(&p2\) escapes to heap" +} + +// in escapes to heap (address of param taken and returned) +func param11(i **int) ***int { // ERROR "moved to heap: i$" + return &i +} + +func caller11a() { + i := 0 // ERROR "moved to heap: i" + p := &i // ERROR "moved to heap: p" + _ = param11(&p) +} + +func caller11b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + sink = param11(&p) // ERROR "param11\(&p\) escapes to heap" +} + +func caller11c() { // GOOD + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" + sink = *param11(&p) // ERROR "\*param11\(&p\) escapes to heap" +} + +func caller11d() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" + p2 := &p + sink = param11(p2) // ERROR "param11\(p2\) escapes to heap" +} + +// &in -> rcvr +type Indir struct { + p ***int +} + +func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$" + r.p = &i +} + +func caller12a() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + var r Indir + r.param12(&p) + _ = r +} + +func caller12b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := &Indir{} // ERROR "caller12b &Indir literal does not escape$" + r.param12(&p) + _ = r +} + +func caller12c() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := Indir{} + r.param12(&p) + sink = r // ERROR "r escapes to heap$" +} + +func caller12d() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := Indir{} + r.param12(&p) + sink = **r.p // ERROR "\* \(\*r\.p\) escapes to heap" +} + +// in -> value rcvr +type Val struct { + p **int +} + +func (v Val) param13(i *int) { // ERROR "Val.param13 v does not escape$" "leaking param: i$" + *v.p = i +} + +func caller13a() { + i := 0 // ERROR "moved to heap: i$" + var p *int + var v Val + v.p = &p + v.param13(&i) + _ = v +} + +func caller13b() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := Val{&p} + v.param13(&i) + _ = v +} + +func caller13c() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" + v.param13(&i) + _ = v +} + +func caller13d() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + var v Val + v.p = &p + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13e() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + v := Val{&p} + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13f() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + v := &Val{&p} // ERROR "&Val literal escapes to heap$" + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13g() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := Val{&p} + v.param13(&i) + sink = *v.p // ERROR "\*v\.p escapes to heap" +} + +func caller13h() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" + v.param13(&i) + sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" +} + +type Node struct { + p *Node +} + +var Sink *Node + +func f(x *Node) { // ERROR "leaking param content: x" + Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" +} + +func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0" + return &Node{x.p} // ERROR "&Node literal escapes to heap" +} + +func h(x *Node) { // ERROR "leaking param: x" + y := &Node{x} // ERROR "h &Node literal does not escape" + Sink = g(y) + f(y) +} + +// interface(in) -> out +// See also issue 29353. + +// Convert to a non-direct interface, require an allocation and +// copy x to heap (not to result). +func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" + return x // ERROR "x escapes to heap" +} + +// Convert to a direct interface, does not need an allocation. +// So x only leaks to result. +func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0" + return x // ERROR "x escapes to heap" +} diff --git a/test/oldescape_struct_return.go b/test/oldescape_struct_return.go new file mode 100644 index 00000000000..5088cf863cf --- /dev/null +++ b/test/oldescape_struct_return.go @@ -0,0 +1,74 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2015 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. + +// Test escape analysis for function parameters. + +package foo + +var Ssink *string + +type U struct { + _sp *string + _spp **string +} + +func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$" + return U{sp, spp} +} + +func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$" + return U{*spp, spp} +} + +func tA1() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + _ = u + println(s) +} + +func tA2() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + println(*u._sp) +} + +func tA3() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + println(**u._spp) +} + +func tB1() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + _ = u + println(s) +} + +func tB2() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + println(*u._sp) +} + +func tB3() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + println(**u._spp) +}