Source file test/escape5.go

     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 (
    13  	"runtime"
    14  	"unsafe"
    15  )
    16  
    17  func noleak(p *int) int { // ERROR "p does not escape"
    18  	return *p
    19  }
    20  
    21  func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
    22  	return p
    23  }
    24  
    25  func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
    26  	return p, p
    27  }
    28  
    29  func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
    30  	return p, q
    31  }
    32  
    33  func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
    34  	return leaktoret22(q, p)
    35  }
    36  
    37  func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
    38  	r, s := leaktoret22(q, p)
    39  	return r, s
    40  }
    41  
    42  func 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  
    47  func 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  
    52  func 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  
    57  var gp *int
    58  
    59  func leaktosink(p *int) *int { // ERROR "leaking param: p"
    60  	gp = p
    61  	return p
    62  }
    63  
    64  func f1() {
    65  	var x int
    66  	p := noleak(&x)
    67  	_ = p
    68  }
    69  
    70  func f2() {
    71  	var x int
    72  	p := leaktoret(&x)
    73  	_ = p
    74  }
    75  
    76  func f3() {
    77  	var x int // ERROR "moved to heap: x"
    78  	p := leaktoret(&x)
    79  	gp = p
    80  }
    81  
    82  func f4() {
    83  	var x int // ERROR "moved to heap: x"
    84  	p, q := leaktoret2(&x)
    85  	gp = p
    86  	gp = q
    87  }
    88  
    89  func f5() {
    90  	var x int
    91  	leaktoret22(leaktoret2(&x))
    92  }
    93  
    94  func f6() {
    95  	var x int // ERROR "moved to heap: x"
    96  	px1, px2 := leaktoret22(leaktoret2(&x))
    97  	gp = px1
    98  	_ = px2
    99  }
   100  
   101  type T struct{ x int }
   102  
   103  func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
   104  	t.x += u
   105  	return t, true
   106  }
   107  
   108  func f7() *T {
   109  	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
   110  	return r
   111  }
   112  
   113  func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
   114  	return leakrecursive2(q, p)
   115  }
   116  
   117  func 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  
   125  var global interface{}
   126  
   127  type T1 struct {
   128  	X *int
   129  }
   130  
   131  type T2 struct {
   132  	Y *T1
   133  }
   134  
   135  func 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  
   146  func f9() {
   147  	var j T1 // ERROR "moved to heap: j"
   148  	f8(&j)
   149  }
   150  
   151  func 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, 1 << 30\) escapes to heap"
   155  	_ = x[0] + y[0]
   156  }
   157  
   158  // Test for issue 19687 (passing to unnamed parameters does not escape).
   159  func f11(**int) {
   160  }
   161  func f12(_ **int) {
   162  }
   163  func 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).
   171  type U int
   172  
   173  func (*U) M()   {}
   174  func (_ *U) N() {}
   175  
   176  func _() {
   177  	var u U
   178  	u.M()
   179  	u.N()
   180  }
   181  
   182  func fbad24305() {
   183  	// BAD u should not be heap allocated
   184  	var u U // ERROR "moved to heap: u"
   185  	(*U).M(&u)
   186  	(*U).N(&u)
   187  }
   188  
   189  // Issue 24730: taking address in a loop causes unnecessary escape
   190  type T24730 struct {
   191  	x [64]byte
   192  }
   193  
   194  func (t *T24730) g() { // ERROR "t does not escape"
   195  	y := t.x[:]
   196  	for i := range t.x[:] {
   197  		y = t.x[:]
   198  		y[i] = 1
   199  	}
   200  
   201  	var z *byte
   202  	for i := range t.x[:] {
   203  		z = &t.x[i]
   204  		*z = 2
   205  	}
   206  }
   207  
   208  // Issue 15730: copy causes unnecessary escape
   209  
   210  var sink []byte
   211  var sink2 []int
   212  var sink3 []*int
   213  
   214  func f15730a(args ...interface{}) { // ERROR "args does not escape"
   215  	for _, arg := range args {
   216  		switch a := arg.(type) {
   217  		case string:
   218  			copy(sink, a)
   219  		}
   220  	}
   221  }
   222  
   223  func f15730b(args ...interface{}) { // ERROR "args does not escape"
   224  	for _, arg := range args {
   225  		switch a := arg.(type) {
   226  		case []int:
   227  			copy(sink2, a)
   228  		}
   229  	}
   230  }
   231  
   232  func f15730c(args ...interface{}) { // ERROR "leaking param content: args"
   233  	for _, arg := range args {
   234  		switch a := arg.(type) {
   235  		case []*int:
   236  			// copy pointerful data should cause escape
   237  			copy(sink3, a)
   238  		}
   239  	}
   240  }
   241  
   242  // Issue 29000: unnamed parameter is not handled correctly
   243  
   244  var sink4 interface{}
   245  var alwaysFalse = false
   246  
   247  func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
   248  	sink4 = x
   249  	if alwaysFalse {
   250  		g29000()
   251  	}
   252  }
   253  
   254  func g29000() {
   255  	x := 1
   256  	f29000(2, x) // ERROR "x escapes to heap"
   257  }
   258  
   259  // Issue 28369: taking an address of a parameter and converting it into a uintptr causes an
   260  // unnecessary escape.
   261  
   262  var sink28369 uintptr
   263  
   264  func f28369(n int) int {
   265  	if n == 0 {
   266  		sink28369 = uintptr(unsafe.Pointer(&n))
   267  		return n
   268  	}
   269  
   270  	return 1 + f28369(n-1)
   271  }
   272  
   273  // Issue 44614: parameters that flow to a heap-allocated result
   274  // parameter must be recorded as a heap-flow rather than a
   275  // result-flow.
   276  
   277  // N.B., must match "leaking param: p",
   278  // but *not* "leaking param: p to result r level=0".
   279  func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r"
   280  	sink4 = &r
   281  	return p
   282  }
   283  

View as plain text