Home | History | Annotate | Download | only in test
      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 
     10 package foo
     11 
     12 import "runtime"
     13 
     14 func noleak(p *int) int { // ERROR "p does not escape"
     15 	return *p
     16 }
     17 
     18 func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
     19 	return p
     20 }
     21 
     22 func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
     23 	return p, p
     24 }
     25 
     26 func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
     27 	return p, q
     28 }
     29 
     30 func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
     31 	return leaktoret22(q, p)
     32 }
     33 
     34 func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
     35 	r, s := leaktoret22(q, p)
     36 	return r, s
     37 }
     38 
     39 func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
     40 	r, s = leaktoret22(q, p)
     41 	return
     42 }
     43 
     44 func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
     45 	r, s = leaktoret22(q, p)
     46 	return r, s
     47 }
     48 
     49 func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
     50 	rr, ss := leaktoret22(q, p)
     51 	return rr, ss
     52 }
     53 
     54 var gp *int
     55 
     56 func leaktosink(p *int) *int { // ERROR "leaking param: p"
     57 	gp = p
     58 	return p
     59 }
     60 
     61 func f1() {
     62 	var x int
     63 	p := noleak(&x) // ERROR "&x does not escape"
     64 	_ = p
     65 }
     66 
     67 func f2() {
     68 	var x int
     69 	p := leaktoret(&x) // ERROR "&x does not escape"
     70 	_ = p
     71 }
     72 
     73 func f3() {
     74 	var x int          // ERROR "moved to heap: x"
     75 	p := leaktoret(&x) // ERROR "&x escapes to heap"
     76 	gp = p
     77 }
     78 
     79 func f4() {
     80 	var x int              // ERROR "moved to heap: x"
     81 	p, q := leaktoret2(&x) // ERROR "&x escapes to heap"
     82 	gp = p
     83 	gp = q
     84 }
     85 
     86 func f5() {
     87 	var x int
     88 	leaktoret22(leaktoret2(&x)) // ERROR "&x does not escape"
     89 }
     90 
     91 func f6() {
     92 	var x int                               // ERROR "moved to heap: x"
     93 	px1, px2 := leaktoret22(leaktoret2(&x)) // ERROR "&x escapes to heap"
     94 	gp = px1
     95 	_ = px2
     96 }
     97 
     98 type T struct{ x int }
     99 
    100 func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
    101 	t.x += u
    102 	return t, true
    103 }
    104 
    105 func f7() *T {
    106 	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
    107 	return r
    108 }
    109 
    110 func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
    111 	return leakrecursive2(q, p)
    112 }
    113 
    114 func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
    115 	if *p > *q {
    116 		return leakrecursive1(q, p)
    117 	}
    118 	// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges.
    119 	return p, q
    120 }
    121 
    122 var global interface{}
    123 
    124 type T1 struct {
    125 	X *int
    126 }
    127 
    128 type T2 struct {
    129 	Y *T1
    130 }
    131 
    132 func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p"
    133 	if p == nil {
    134 		k = T2{}
    135 		return
    136 	}
    137 
    138 	// should make p leak always
    139 	global = p // ERROR "p escapes to heap"
    140 	return T2{p}
    141 }
    142 
    143 func f9() {
    144 	var j T1 // ERROR "moved to heap: j"
    145 	f8(&j)   // ERROR "&j escapes to heap"
    146 }
    147 
    148 func f10() {
    149 	// These don't escape but are too big for the stack
    150 	var x [1 << 30]byte         // ERROR "moved to heap: x"
    151 	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
    152 	_ = x[0] + y[0]
    153 }
    154 
    155 // Test for issue 19687 (passing to unnamed parameters does not escape).
    156 func f11(**int) {
    157 }
    158 func f12(_ **int) {
    159 }
    160 func f13() {
    161 	var x *int
    162 	f11(&x)               // ERROR "&x does not escape"
    163 	f12(&x)               // ERROR "&x does not escape"
    164 	runtime.KeepAlive(&x) // ERROR "&x does not escape"
    165 }
    166