Source file test/escape_closure.go

     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 closure arguments.
     8  
     9  package escape
    10  
    11  var sink interface{}
    12  
    13  func ClosureCallArgs0() {
    14  	x := 0
    15  	func(p *int) { // ERROR "p does not escape" "func literal does not escape"
    16  		*p = 1
    17  	}(&x)
    18  }
    19  
    20  func ClosureCallArgs1() {
    21  	x := 0
    22  	for {
    23  		func(p *int) { // ERROR "p does not escape" "func literal does not escape"
    24  			*p = 1
    25  		}(&x)
    26  	}
    27  }
    28  
    29  func ClosureCallArgs2() {
    30  	for {
    31  		x := 0
    32  		func(p *int) { // ERROR "p does not escape" "func literal does not escape"
    33  			*p = 1
    34  		}(&x)
    35  	}
    36  }
    37  
    38  func ClosureCallArgs3() {
    39  	x := 0         // ERROR "moved to heap: x"
    40  	func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
    41  		sink = p
    42  	}(&x)
    43  }
    44  
    45  func ClosureCallArgs4() {
    46  	x := 0
    47  	_ = func(p *int) *int { // ERROR "leaking param: p to result ~r0" "func literal does not escape"
    48  		return p
    49  	}(&x)
    50  }
    51  
    52  func ClosureCallArgs5() {
    53  	x := 0 // ERROR "moved to heap: x"
    54  	// TODO(mdempsky): We get "leaking param: p" here because the new escape analysis pass
    55  	// can tell that p flows directly to sink, but it's a little weird. Re-evaluate.
    56  	sink = func(p *int) *int { // ERROR "leaking param: p" "func literal does not escape"
    57  		return p
    58  	}(&x)
    59  }
    60  
    61  func ClosureCallArgs6() {
    62  	x := 0         // ERROR "moved to heap: x"
    63  	func(p *int) { // ERROR "moved to heap: p" "func literal does not escape"
    64  		sink = &p
    65  	}(&x)
    66  }
    67  
    68  func ClosureCallArgs7() {
    69  	var pp *int
    70  	for {
    71  		x := 0         // ERROR "moved to heap: x"
    72  		func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
    73  			pp = p
    74  		}(&x)
    75  	}
    76  	_ = pp
    77  }
    78  
    79  func ClosureCallArgs8() {
    80  	x := 0
    81  	defer func(p *int) { // ERROR "p does not escape" "func literal does not escape"
    82  		*p = 1
    83  	}(&x)
    84  }
    85  
    86  func ClosureCallArgs9() {
    87  	// BAD: x should not leak
    88  	x := 0 // ERROR "moved to heap: x"
    89  	for {
    90  		defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape"
    91  			*p = 1
    92  		}(&x)
    93  	}
    94  }
    95  
    96  func ClosureCallArgs10() {
    97  	for {
    98  		x := 0               // ERROR "moved to heap: x"
    99  		defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape"
   100  			*p = 1
   101  		}(&x)
   102  	}
   103  }
   104  
   105  func ClosureCallArgs11() {
   106  	x := 0               // ERROR "moved to heap: x"
   107  	defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
   108  		sink = p
   109  	}(&x)
   110  }
   111  
   112  func ClosureCallArgs12() {
   113  	x := 0
   114  	defer func(p *int) *int { // ERROR "leaking param: p to result ~r0" "func literal does not escape"
   115  		return p
   116  	}(&x)
   117  }
   118  
   119  func ClosureCallArgs13() {
   120  	x := 0               // ERROR "moved to heap: x"
   121  	defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape"
   122  		sink = &p
   123  	}(&x)
   124  }
   125  
   126  func ClosureCallArgs14() {
   127  	x := 0
   128  	p := &x
   129  	_ = func(p **int) *int { // ERROR "leaking param: p to result ~r0 level=1" "func literal does not escape"
   130  		return *p
   131  	}(&p)
   132  }
   133  
   134  func ClosureCallArgs15() {
   135  	x := 0 // ERROR "moved to heap: x"
   136  	p := &x
   137  	sink = func(p **int) *int { // ERROR "leaking param: p to result ~r0 level=1" "func literal does not escape"
   138  		return *p
   139  	}(&p)
   140  }
   141  
   142  func ClosureLeak1(s string) string { // ERROR "s does not escape"
   143  	t := s + "YYYY"         // ERROR "escapes to heap"
   144  	return ClosureLeak1a(t) // ERROR "... argument does not escape"
   145  }
   146  
   147  // See #14409 -- returning part of captured var leaks it.
   148  func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r0 level=1$"
   149  	return func() string { // ERROR "func literal does not escape"
   150  		return a[0]
   151  	}()
   152  }
   153  
   154  func ClosureLeak2(s string) string { // ERROR "s does not escape"
   155  	t := s + "YYYY"       // ERROR "escapes to heap"
   156  	c := ClosureLeak2a(t) // ERROR "... argument does not escape"
   157  	return c
   158  }
   159  func ClosureLeak2a(a ...string) string { // ERROR "leaking param content: a"
   160  	return ClosureLeak2b(func() string { // ERROR "func literal does not escape"
   161  		return a[0]
   162  	})
   163  }
   164  func ClosureLeak2b(f func() string) string { // ERROR "f does not escape"
   165  	return f()
   166  }
   167  
   168  func ClosureIndirect() {
   169  	f := func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   170  	f(new(int))          // ERROR "new\(int\) does not escape"
   171  
   172  	g := f
   173  	g(new(int)) // ERROR "new\(int\) does not escape"
   174  
   175  	h := nopFunc
   176  	h(new(int)) // ERROR "new\(int\) does not escape"
   177  }
   178  
   179  func nopFunc(p *int) {} // ERROR "p does not escape"
   180  
   181  func ClosureIndirect2() {
   182  	f := func(p *int) *int { return p } // ERROR "leaking param: p to result ~r0 level=0" "func literal does not escape"
   183  
   184  	f(new(int)) // ERROR "new\(int\) does not escape"
   185  
   186  	g := f
   187  	g(new(int)) // ERROR "new\(int\) does not escape"
   188  
   189  	h := nopFunc2
   190  	h(new(int)) // ERROR "new\(int\) does not escape"
   191  }
   192  
   193  func nopFunc2(p *int) *int { return p } // ERROR "leaking param: p to result ~r0 level=0"
   194  
   195  func ClosureIndirectDeclAssign() {
   196  	var f func(p *int)
   197  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   198  	f(new(int))         // ERROR "new\(int\) does not escape"
   199  }
   200  
   201  func ClosureIndirectDeclAssign2() {
   202  	var f func(p *int) *int
   203  	f = func(p *int) *int { return p } // ERROR "leaking param: p to result ~r0 level=0" "func literal does not escape"
   204  	f(new(int))                        // ERROR "new\(int\) does not escape"
   205  }
   206  
   207  func ClosureIndirectDeclAssign3() {
   208  	var f func(p *int)
   209  	f = func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
   210  		sink = p
   211  	}
   212  	f(new(int)) // ERROR "new\(int\) escapes to heap"
   213  }
   214  
   215  func ClosureIndirectDeclReassign() {
   216  	var f func(p *int)
   217  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   218  	f = func(p *int) {  // ERROR "leaking param: p" "func literal does not escape"
   219  		sink = p
   220  	}
   221  	f(new(int)) // ERROR "new\(int\) escapes to heap"
   222  }
   223  
   224  func ClosureIndirectDeclRecursive() {
   225  	var visit func(p *int)
   226  	visit = func(p *int) { // ERROR "p does not escape" "func literal does not escape"
   227  		visit(p)
   228  	}
   229  	visit(new(int)) // ERROR "new\(int\) does not escape"
   230  }
   231  
   232  func ClosureIndirectNilInit() {
   233  	var f func(p *int) = nil
   234  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   235  	f(new(int))         // ERROR "new\(int\) does not escape"
   236  }
   237  
   238  func ClosureIndirectTypedNilInit() {
   239  	var f func(p *int) = (func(*int))(nil)
   240  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   241  	f(new(int))         // ERROR "new\(int\) does not escape"
   242  }
   243  
   244  func ClosureIndirectNestedAssign() {
   245  	var f func(p *int)
   246  	func() { // ERROR "func literal does not escape"
   247  		f = func(p *int) {} // ERROR "p does not escape" "func literal escapes to heap"
   248  	}()
   249  	f(new(int)) // ERROR "new\(int\) does not escape"
   250  }
   251  
   252  func ClosureIndirectNestedAssignLeak() {
   253  	var f func(p *int)
   254  	func() { // ERROR "func literal does not escape"
   255  		f = func(p *int) { // ERROR "leaking param: p" "func literal escapes to heap"
   256  			sink = p
   257  		}
   258  	}()
   259  	f(new(int)) // ERROR "new\(int\) escapes to heap"
   260  }
   261  
   262  func ClosureIndirectTypeSwitch() {
   263  	foo := any(func(a *int) { sink = a }) // ERROR "func literal does not escape" "leaking param: a"
   264  	switch foo := foo.(type) {
   265  	case func(a *int):
   266  		foo(new(int)) // ERROR "new\(int\) escapes to heap"
   267  	}
   268  }
   269  
   270  func ClosureIndirectTypeSwitchReassign() {
   271  	foo := any(func(a *int) { sink = a }) // ERROR "func literal does not escape" "leaking param: a"
   272  	switch foo := foo.(type) {
   273  	case func(a *int):
   274  		foo = func(a *int) {} // ERROR "func literal does not escape" "a does not escape"
   275  		foo(new(int))         // ERROR "new\(int\) escapes to heap"
   276  	}
   277  }
   278  
   279  func ClosureIndirectNilReassign() {
   280  	var f func(p *int)
   281  	f = nil
   282  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   283  	f(new(int))         // ERROR "new\(int\) does not escape"
   284  }
   285  
   286  func ClosureIndirectMultiAssign(b bool) {
   287  	var f func(p *int)
   288  	if b {
   289  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   290  	} else {
   291  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   292  	}
   293  	f(new(int)) // ERROR "new\(int\) does not escape"
   294  }
   295  
   296  func ClosureIndirectMultiAssignNamed(b bool) {
   297  	var f func(*int)
   298  	if b {
   299  		f = nopFunc
   300  	} else {
   301  		f = nopFunc
   302  	}
   303  	f(new(int)) // ERROR "new\(int\) does not escape"
   304  }
   305  
   306  func ClosureIndirectMultiAssignResult(b bool) *int {
   307  	var f func(p *int) *int
   308  	if b {
   309  		f = func(p *int) *int { return p } // ERROR "leaking param: p to result ~r0 level=0" "func literal does not escape"
   310  	} else {
   311  		f = func(p *int) *int { return p } // ERROR "leaking param: p to result ~r0 level=0" "func literal does not escape"
   312  	}
   313  	return f(new(int)) // ERROR "new\(int\) escapes to heap"
   314  }
   315  
   316  func ClosureIndirectMultiAssignSafe(b bool) int {
   317  	var f func(p *int) int
   318  	if b {
   319  		f = func(p *int) int { return *p } // ERROR "p does not escape" "func literal does not escape"
   320  	} else {
   321  		f = func(p *int) int { return 42 } // ERROR "p does not escape" "func literal does not escape"
   322  	}
   323  	return f(new(int)) // ERROR "new\(int\) does not escape"
   324  }
   325  
   326  func ClosureIndirectTripleAssign(x int) {
   327  	var f func(p *int)
   328  	switch x {
   329  	case 1:
   330  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   331  	case 2:
   332  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   333  	default:
   334  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   335  	}
   336  	f(new(int)) // ERROR "new\(int\) does not escape"
   337  }
   338  
   339  func ClosureIndirectReassignInit(b bool) {
   340  	f := func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   341  	if b {
   342  		f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   343  	}
   344  	f(new(int)) // ERROR "new\(int\) does not escape"
   345  }
   346  
   347  func ClosureIndirectNestedMultiAssign(b bool) {
   348  	var f func(p *int)
   349  	f = func(p *int) {} // ERROR "p does not escape" "func literal does not escape"
   350  	func() {            // ERROR "func literal does not escape"
   351  		f = func(p *int) {} // ERROR "p does not escape" "func literal escapes to heap"
   352  	}()
   353  	f(new(int)) // ERROR "new\(int\) does not escape"
   354  }
   355  
   356  type myFloat struct{ v float64 }
   357  
   358  func (f *myFloat) add(p *myFloat) *myFloat { // ERROR "leaking param: f to result ~r0 level=0" "p does not escape"
   359  	f.v += p.v
   360  	return f
   361  }
   362  
   363  func (f *myFloat) sub(p *myFloat) *myFloat { // ERROR "leaking param: f to result ~r0 level=0" "p does not escape"
   364  	f.v -= p.v
   365  	return f
   366  }
   367  
   368  func ClosureIndirectMethodExpr(b bool) {
   369  	var op func(*myFloat, *myFloat) *myFloat
   370  	if b {
   371  		op = (*myFloat).add
   372  	} else {
   373  		op = (*myFloat).sub
   374  	}
   375  	f := &myFloat{1.0} // ERROR "&myFloat{...} does not escape"
   376  	g := &myFloat{2.0} // ERROR "&myFloat{...} does not escape"
   377  	op(f, g)
   378  }
   379  
   380  func ClosureIndirectMethodExprMixed(b bool) {
   381  	var op func(*myFloat, *myFloat) *myFloat
   382  	if b {
   383  		op = (*myFloat).add
   384  	} else {
   385  		op = func(f, g *myFloat) *myFloat { // ERROR "f does not escape" "g does not escape" "func literal does not escape"
   386  			return nil
   387  		}
   388  	}
   389  	f := &myFloat{1.0} // ERROR "&myFloat{...} does not escape"
   390  	g := &myFloat{2.0} // ERROR "&myFloat{...} does not escape"
   391  	op(f, g)
   392  }
   393  

View as plain text