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 ~r1" "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 ~r1" "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 ~r1 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 content: p" "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 ~r1 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  

View as plain text