1// errorcheck -0 -m -l 2 3// Copyright 2012 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7// Test, using compiler diagnostic flags, that the escape analysis is working. 8// Compiles but does not run. Inlining is disabled. 9 10package foo 11 12import ( 13 "runtime" 14 "unsafe" 15) 16 17func noleak(p *int) int { // ERROR "p does not escape" 18 return *p 19} 20 21func leaktoret(p *int) *int { // ERROR "leaking param: p to result" 22 return p 23} 24 25func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: p to result ~r1" 26 return p, p 27} 28 29func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: q to result ~r1" 30 return p, q 31} 32 33func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" 34 return leaktoret22(q, p) 35} 36 37func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0" 38 r, s := leaktoret22(q, p) 39 return r, s 40} 41 42func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" 43 r, s = leaktoret22(q, p) 44 return 45} 46 47func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" 48 r, s = leaktoret22(q, p) 49 return r, s 50} 51 52func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" 53 rr, ss := leaktoret22(q, p) 54 return rr, ss 55} 56 57var gp *int 58 59func leaktosink(p *int) *int { // ERROR "leaking param: p" 60 gp = p 61 return p 62} 63 64func f1() { 65 var x int 66 p := noleak(&x) 67 _ = p 68} 69 70func f2() { 71 var x int 72 p := leaktoret(&x) 73 _ = p 74} 75 76func f3() { 77 var x int // ERROR "moved to heap: x" 78 p := leaktoret(&x) 79 gp = p 80} 81 82func f4() { 83 var x int // ERROR "moved to heap: x" 84 p, q := leaktoret2(&x) 85 gp = p 86 gp = q 87} 88 89func f5() { 90 var x int 91 leaktoret22(leaktoret2(&x)) 92} 93 94func f6() { 95 var x int // ERROR "moved to heap: x" 96 px1, px2 := leaktoret22(leaktoret2(&x)) 97 gp = px1 98 _ = px2 99} 100 101type T struct{ x int } 102 103func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result" 104 t.x += u 105 return t, true 106} 107 108func f7() *T { 109 r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap" 110 return r 111} 112 113func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" 114 return leakrecursive2(q, p) 115} 116 117func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" 118 if *p > *q { 119 return leakrecursive1(q, p) 120 } 121 // without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges. 122 return p, q 123} 124 125var global interface{} 126 127type T1 struct { 128 X *int 129} 130 131type T2 struct { 132 Y *T1 133} 134 135func f8(p *T1) (k T2) { // ERROR "leaking param: p$" 136 if p == nil { 137 k = T2{} 138 return 139 } 140 141 // should make p leak always 142 global = p 143 return T2{p} 144} 145 146func f9() { 147 var j T1 // ERROR "moved to heap: j" 148 f8(&j) 149} 150 151func f10() { 152 // These don't escape but are too big for the stack 153 var x [1 << 30]byte // ERROR "moved to heap: x" 154 var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1073741824\) escapes to heap" 155 _ = x[0] + y[0] 156} 157 158// Test for issue 19687 (passing to unnamed parameters does not escape). 159func f11(**int) { 160} 161func f12(_ **int) { 162} 163func f13() { 164 var x *int 165 f11(&x) 166 f12(&x) 167 runtime.KeepAlive(&x) 168} 169 170// Test for issue 24305 (passing to unnamed receivers does not escape). 171type U int 172 173func (*U) M() {} 174func (_ *U) N() {} 175 176func fbad24305a() { 177 var u U 178 u.M() 179 u.N() 180} 181 182func fbad24305b() { 183 var u U 184 (*U).M(&u) 185 (*U).N(&u) 186} 187 188// Issue 24730: taking address in a loop causes unnecessary escape 189type T24730 struct { 190 x [64]byte 191} 192 193func (t *T24730) g() { // ERROR "t does not escape" 194 y := t.x[:] 195 for i := range t.x[:] { 196 y = t.x[:] 197 y[i] = 1 198 } 199 200 var z *byte 201 for i := range t.x[:] { 202 z = &t.x[i] 203 *z = 2 204 } 205} 206 207// Issue 15730: copy causes unnecessary escape 208 209var sink []byte 210var sink2 []int 211var sink3 []*int 212 213func f15730a(args ...interface{}) { // ERROR "args does not escape" 214 for _, arg := range args { 215 switch a := arg.(type) { 216 case string: 217 copy(sink, a) 218 } 219 } 220} 221 222func f15730b(args ...interface{}) { // ERROR "args does not escape" 223 for _, arg := range args { 224 switch a := arg.(type) { 225 case []int: 226 copy(sink2, a) 227 } 228 } 229} 230 231func f15730c(args ...interface{}) { // ERROR "leaking param content: args" 232 for _, arg := range args { 233 switch a := arg.(type) { 234 case []*int: 235 // copy pointerful data should cause escape 236 copy(sink3, a) 237 } 238 } 239} 240 241// Issue 29000: unnamed parameter is not handled correctly 242 243var sink4 interface{} 244var alwaysFalse = false 245 246func f29000(_ int, x interface{}) { // ERROR "leaking param: x" 247 sink4 = x 248 if alwaysFalse { 249 g29000() 250 } 251} 252 253func g29000() { 254 x := 1 255 f29000(2, x) // ERROR "x escapes to heap" 256} 257 258// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an 259// unnecessary escape. 260 261var sink28369 uintptr 262 263func f28369(n int) int { 264 if n == 0 { 265 sink28369 = uintptr(unsafe.Pointer(&n)) 266 return n 267 } 268 269 return 1 + f28369(n-1) 270} 271 272// Issue 44614: parameters that flow to a heap-allocated result 273// parameter must be recorded as a heap-flow rather than a 274// result-flow. 275 276// N.B., must match "leaking param: p", 277// but *not* "leaking param: p to result r level=0". 278func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r" 279 sink4 = &r 280 return p 281} 282