1// errorcheck -0 -m -l 2 3// Copyright 2015 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 escape analysis for function parameters. 8 9// In this test almost everything is BAD except the simplest cases 10// where input directly flows to output. 11 12package escape 13 14func zero() int { return 0 } 15 16var sink interface{} 17 18// in -> out 19func param0(p *int) *int { // ERROR "leaking param: p to result ~r0" 20 return p 21} 22 23func caller0a() { 24 i := 0 25 _ = param0(&i) 26} 27 28func caller0b() { 29 i := 0 // ERROR "moved to heap: i$" 30 sink = param0(&i) 31} 32 33// in, in -> out, out 34func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r0" "leaking param: p2 to result ~r1" 35 return p1, p2 36} 37 38func caller1() { 39 i := 0 // ERROR "moved to heap: i$" 40 j := 0 41 sink, _ = param1(&i, &j) 42} 43 44// in -> other in 45func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "p2 does not escape$" 46 *p2 = p1 47} 48 49func caller2a() { 50 i := 0 // ERROR "moved to heap: i$" 51 var p *int 52 param2(&i, &p) 53 _ = p 54} 55 56func caller2b() { 57 i := 0 // ERROR "moved to heap: i$" 58 var p *int 59 param2(&i, &p) 60 sink = p 61} 62 63func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape" 64 p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]" 65} 66 67func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p" 68 // Function call inside index disables self-assignment case to trigger. 69 p.pairs[zero()] = p.pairs[1] 70 p.pairs[zero()+1] = p.pairs[1] 71} 72 73type PairOfPairs struct { 74 pairs [2]*Pair 75} 76 77type BoxedPair struct { 78 pair *Pair 79} 80 81type WrappedPair struct { 82 pair Pair 83} 84 85func leakParam(x interface{}) { // ERROR "leaking param: x" 86 sink = x 87} 88 89func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box" 90 box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" 91 sink = box.pair.p2 92} 93 94func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box" 95 box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" 96 sink = box.pair 97} 98 99func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box" 100 box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" 101 leakParam(box.pair.p2) 102} 103 104func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box" 105 box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" 106 leakParam(box.pair) 107} 108 109func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" 110 box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2" 111 leakParam(box2.pair.p2) 112} 113 114func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" 115 box1.pair.p1 = box2.pair.p1 116} 117 118func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" 119 p1.pairs[0] = p2.pairs[1] 120} 121 122func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" 123 p1.pairs[0].p1 = p2.pairs[1].p1 124} 125 126func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape" 127 box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" 128} 129 130func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape" 131 w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2" 132} 133 134// in -> in 135type Pair struct { 136 p1 *int 137 p2 *int 138} 139 140func param3(p *Pair) { // ERROR "p does not escape" 141 p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2" 142} 143 144func caller3a() { 145 i := 0 146 j := 0 147 p := Pair{&i, &j} 148 param3(&p) 149 _ = p 150} 151 152func caller3b() { 153 i := 0 // ERROR "moved to heap: i$" 154 j := 0 // ERROR "moved to heap: j$" 155 p := Pair{&i, &j} 156 param3(&p) 157 sink = p // ERROR "p escapes to heap$" 158} 159 160// in -> rcvr 161func (p *Pair) param4(i *int) { // ERROR "p does not escape$" "leaking param: i$" 162 p.p1 = i 163} 164 165func caller4a() { 166 i := 0 // ERROR "moved to heap: i$" 167 p := Pair{} 168 p.param4(&i) 169 _ = p 170} 171 172func caller4b() { 173 i := 0 // ERROR "moved to heap: i$" 174 p := Pair{} 175 p.param4(&i) 176 sink = p // ERROR "p escapes to heap$" 177} 178 179// in -> heap 180func param5(i *int) { // ERROR "leaking param: i$" 181 sink = i 182} 183 184func caller5() { 185 i := 0 // ERROR "moved to heap: i$" 186 param5(&i) 187} 188 189// *in -> heap 190func param6(i ***int) { // ERROR "leaking param content: i$" 191 sink = *i 192} 193 194func caller6a() { 195 i := 0 // ERROR "moved to heap: i$" 196 p := &i // ERROR "moved to heap: p$" 197 p2 := &p 198 param6(&p2) 199} 200 201// **in -> heap 202func param7(i ***int) { // ERROR "leaking param content: i$" 203 sink = **i 204} 205 206func caller7() { 207 i := 0 // ERROR "moved to heap: i$" 208 p := &i 209 p2 := &p 210 param7(&p2) 211} 212 213// **in -> heap 214func param8(i **int) { // ERROR "i does not escape$" 215 sink = **i // ERROR "\*\(\*i\) escapes to heap" 216} 217 218func caller8() { 219 i := 0 220 p := &i 221 param8(&p) 222} 223 224// *in -> out 225func param9(p ***int) **int { // ERROR "leaking param: p to result ~r0 level=1" 226 return *p 227} 228 229func caller9a() { 230 i := 0 231 p := &i 232 p2 := &p 233 _ = param9(&p2) 234} 235 236func caller9b() { 237 i := 0 // ERROR "moved to heap: i$" 238 p := &i // ERROR "moved to heap: p$" 239 p2 := &p 240 sink = param9(&p2) 241} 242 243// **in -> out 244func param10(p ***int) *int { // ERROR "leaking param: p to result ~r0 level=2" 245 return **p 246} 247 248func caller10a() { 249 i := 0 250 p := &i 251 p2 := &p 252 _ = param10(&p2) 253} 254 255func caller10b() { 256 i := 0 // ERROR "moved to heap: i$" 257 p := &i 258 p2 := &p 259 sink = param10(&p2) 260} 261 262// in escapes to heap (address of param taken and returned) 263func param11(i **int) ***int { // ERROR "moved to heap: i$" 264 return &i 265} 266 267func caller11a() { 268 i := 0 // ERROR "moved to heap: i" 269 p := &i // ERROR "moved to heap: p" 270 _ = param11(&p) 271} 272 273func caller11b() { 274 i := 0 // ERROR "moved to heap: i$" 275 p := &i // ERROR "moved to heap: p$" 276 sink = param11(&p) 277} 278 279func caller11c() { // GOOD 280 i := 0 // ERROR "moved to heap: i$" 281 p := &i // ERROR "moved to heap: p" 282 sink = *param11(&p) 283} 284 285func caller11d() { 286 i := 0 // ERROR "moved to heap: i$" 287 p := &i // ERROR "moved to heap: p" 288 p2 := &p 289 sink = param11(p2) 290} 291 292// &in -> rcvr 293type Indir struct { 294 p ***int 295} 296 297func (r *Indir) param12(i **int) { // ERROR "r does not escape$" "moved to heap: i$" 298 r.p = &i 299} 300 301func caller12a() { 302 i := 0 // ERROR "moved to heap: i$" 303 p := &i // ERROR "moved to heap: p$" 304 var r Indir 305 r.param12(&p) 306 _ = r 307} 308 309func caller12b() { 310 i := 0 // ERROR "moved to heap: i$" 311 p := &i // ERROR "moved to heap: p$" 312 r := &Indir{} // ERROR "&Indir{} does not escape$" 313 r.param12(&p) 314 _ = r 315} 316 317func caller12c() { 318 i := 0 // ERROR "moved to heap: i$" 319 p := &i // ERROR "moved to heap: p$" 320 r := Indir{} 321 r.param12(&p) 322 sink = r 323} 324 325func caller12d() { 326 i := 0 // ERROR "moved to heap: i$" 327 p := &i // ERROR "moved to heap: p$" 328 r := Indir{} 329 r.param12(&p) 330 sink = **r.p 331} 332 333// in -> value rcvr 334type Val struct { 335 p **int 336} 337 338func (v Val) param13(i *int) { // ERROR "v does not escape$" "leaking param: i$" 339 *v.p = i 340} 341 342func caller13a() { 343 i := 0 // ERROR "moved to heap: i$" 344 var p *int 345 var v Val 346 v.p = &p 347 v.param13(&i) 348 _ = v 349} 350 351func caller13b() { 352 i := 0 // ERROR "moved to heap: i$" 353 var p *int 354 v := Val{&p} 355 v.param13(&i) 356 _ = v 357} 358 359func caller13c() { 360 i := 0 // ERROR "moved to heap: i$" 361 var p *int 362 v := &Val{&p} // ERROR "&Val{...} does not escape$" 363 v.param13(&i) 364 _ = v 365} 366 367func caller13d() { 368 i := 0 // ERROR "moved to heap: i$" 369 var p *int // ERROR "moved to heap: p$" 370 var v Val 371 v.p = &p 372 v.param13(&i) 373 sink = v 374} 375 376func caller13e() { 377 i := 0 // ERROR "moved to heap: i$" 378 var p *int // ERROR "moved to heap: p$" 379 v := Val{&p} 380 v.param13(&i) 381 sink = v 382} 383 384func caller13f() { 385 i := 0 // ERROR "moved to heap: i$" 386 var p *int // ERROR "moved to heap: p$" 387 v := &Val{&p} // ERROR "&Val{...} escapes to heap$" 388 v.param13(&i) 389 sink = v 390} 391 392func caller13g() { 393 i := 0 // ERROR "moved to heap: i$" 394 var p *int 395 v := Val{&p} 396 v.param13(&i) 397 sink = *v.p 398} 399 400func caller13h() { 401 i := 0 // ERROR "moved to heap: i$" 402 var p *int 403 v := &Val{&p} // ERROR "&Val{...} does not escape$" 404 v.param13(&i) 405 sink = **v.p // ERROR "\*\(\*v\.p\) escapes to heap" 406} 407 408type Node struct { 409 p *Node 410} 411 412var Sink *Node 413 414func f(x *Node) { // ERROR "leaking param content: x" 415 Sink = &Node{x.p} // ERROR "&Node{...} escapes to heap" 416} 417 418func g(x *Node) *Node { // ERROR "leaking param content: x" 419 return &Node{x.p} // ERROR "&Node{...} escapes to heap" 420} 421 422func h(x *Node) { // ERROR "leaking param: x" 423 y := &Node{x} // ERROR "&Node{...} does not escape" 424 Sink = g(y) 425 f(y) 426} 427 428// interface(in) -> out 429// See also issue 29353. 430 431// Convert to a non-direct interface, require an allocation and 432// copy x to heap (not to result). 433func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" 434 return x // ERROR "x escapes to heap" 435} 436 437// Convert to a direct interface, does not need an allocation. 438// So x only leaks to result. 439func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r0 level=0" 440 return x 441} 442