-// 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
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$"
}
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$"
}
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
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$"
}
// 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
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)
}
-// 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
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$"
}
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$"
}
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
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$"
}
// 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
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)
}
-// 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
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
-// 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
-// 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
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
-// 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
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)
}
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)
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)
}
}
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)
}
}
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)
}
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)
}
}
// 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]
}()
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()
}
-// 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
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"
}
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"
}
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"
}
-// 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
{
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"
}
-// 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
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"
}
-// 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
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}
}
-// 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
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...)
-// 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
}
//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)
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)
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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$"
+}
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 {
-// 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
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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"
+}
--- /dev/null
+// 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"
+}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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"
+}
--- /dev/null
+// 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)
+ }
+}
--- /dev/null
+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
+}
--- /dev/null
+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
+}
--- /dev/null
+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"
+ }
+}
--- /dev/null
+// 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"
+*/
--- /dev/null
+// 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"
+}
--- /dev/null
+// 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)
+}