diff options
Diffstat (limited to 'test/escape5.go')
-rw-r--r-- | test/escape5.go | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/test/escape5.go b/test/escape5.go new file mode 100644 index 0000000..089130d --- /dev/null +++ b/test/escape5.go @@ -0,0 +1,281 @@ +// errorcheck -0 -m -l + +// 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" + "unsafe" +) + +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 ~r0" "leaking param: p to result ~r1" + return p, p +} + +func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: q to result ~r1" + return p, q +} + +func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" + return leaktoret22(q, p) +} + +func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" + 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$" + if p == nil { + k = T2{} + return + } + + // should make p leak always + global = p + 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) +} + +// Test for issue 24305 (passing to unnamed receivers does not escape). +type U int + +func (*U) M() {} +func (_ *U) N() {} + +func fbad24305a() { + var u U + u.M() + u.N() +} + +func fbad24305b() { + var u U + (*U).M(&u) + (*U).N(&u) +} + +// 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" +} + +// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an +// unnecessary escape. + +var sink28369 uintptr + +func f28369(n int) int { + if n == 0 { + sink28369 = uintptr(unsafe.Pointer(&n)) + return n + } + + return 1 + f28369(n-1) +} + +// Issue 44614: parameters that flow to a heap-allocated result +// parameter must be recorded as a heap-flow rather than a +// result-flow. + +// N.B., must match "leaking param: p", +// but *not* "leaking param: p to result r level=0". +func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r" + sink4 = &r + return p +} |