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 ~r0" "leaking param: p to result ~r1"
    26  	return p, p
    27  }
    28  
    29  func 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  
    33  func 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  
    37  func 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  
    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, 1073741824\) 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 fbad24305a() {
   177  	var u U
   178  	u.M()
   179  	u.N()
   180  }
   181  
   182  func 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
   189  type T24730 struct {
   190  	x [64]byte
   191  }
   192  
   193  func (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  
   209  var sink []byte
   210  var sink2 []int
   211  var sink3 []*int
   212  
   213  func 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  
   222  func 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  
   231  func 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  
   243  var sink4 interface{}
   244  var alwaysFalse = false
   245  
   246  func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
   247  	sink4 = x
   248  	if alwaysFalse {
   249  		g29000()
   250  	}
   251  }
   252  
   253  func 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  
   261  var sink28369 uintptr
   262  
   263  func 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".
   278  func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r"
   279  	sink4 = &r
   280  	return p
   281  }
   282  

View as plain text