Source file test/escape_param.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 function parameters.
     8  
     9  // In this test almost everything is BAD except the simplest cases
    10  // where input directly flows to output.
    11  
    12  package escape
    13  
    14  func zero() int { return 0 }
    15  
    16  var sink interface{}
    17  
    18  // in -> out
    19  func param0(p *int) *int { // ERROR "leaking param: p to result ~r0"
    20  	return p
    21  }
    22  
    23  func caller0a() {
    24  	i := 0
    25  	_ = param0(&i)
    26  }
    27  
    28  func caller0b() {
    29  	i := 0 // ERROR "moved to heap: i$"
    30  	sink = param0(&i)
    31  }
    32  
    33  // in, in -> out, out
    34  func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r0" "leaking param: p2 to result ~r1"
    35  	return p1, p2
    36  }
    37  
    38  func caller1() {
    39  	i := 0 // ERROR "moved to heap: i$"
    40  	j := 0
    41  	sink, _ = param1(&i, &j)
    42  }
    43  
    44  // in -> other in
    45  func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "p2 does not escape$"
    46  	*p2 = p1
    47  }
    48  
    49  func caller2a() {
    50  	i := 0 // ERROR "moved to heap: i$"
    51  	var p *int
    52  	param2(&i, &p)
    53  	_ = p
    54  }
    55  
    56  func caller2b() {
    57  	i := 0 // ERROR "moved to heap: i$"
    58  	var p *int
    59  	param2(&i, &p)
    60  	sink = p
    61  }
    62  
    63  func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape"
    64  	p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]"
    65  }
    66  
    67  func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p"
    68  	// Function call inside index disables self-assignment case to trigger.
    69  	p.pairs[zero()] = p.pairs[1]
    70  	p.pairs[zero()+1] = p.pairs[1]
    71  }
    72  
    73  type PairOfPairs struct {
    74  	pairs [2]*Pair
    75  }
    76  
    77  type BoxedPair struct {
    78  	pair *Pair
    79  }
    80  
    81  type WrappedPair struct {
    82  	pair Pair
    83  }
    84  
    85  func leakParam(x interface{}) { // ERROR "leaking param: x"
    86  	sink = x
    87  }
    88  
    89  func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box"
    90  	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
    91  	sink = box.pair.p2
    92  }
    93  
    94  func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box"
    95  	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
    96  	sink = box.pair
    97  }
    98  
    99  func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box"
   100  	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
   101  	leakParam(box.pair.p2)
   102  }
   103  
   104  func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box"
   105  	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
   106  	leakParam(box.pair)
   107  }
   108  
   109  func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape"
   110  	box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2"
   111  	leakParam(box2.pair.p2)
   112  }
   113  
   114  func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape"
   115  	box1.pair.p1 = box2.pair.p1
   116  }
   117  
   118  func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape"
   119  	p1.pairs[0] = p2.pairs[1]
   120  }
   121  
   122  func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape"
   123  	p1.pairs[0].p1 = p2.pairs[1].p1
   124  }
   125  
   126  func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape"
   127  	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
   128  }
   129  
   130  func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape"
   131  	w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2"
   132  }
   133  
   134  // in -> in
   135  type Pair struct {
   136  	p1 *int
   137  	p2 *int
   138  }
   139  
   140  func param3(p *Pair) { // ERROR "p does not escape"
   141  	p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2"
   142  }
   143  
   144  func caller3a() {
   145  	i := 0
   146  	j := 0
   147  	p := Pair{&i, &j}
   148  	param3(&p)
   149  	_ = p
   150  }
   151  
   152  func caller3b() {
   153  	i := 0 // ERROR "moved to heap: i$"
   154  	j := 0 // ERROR "moved to heap: j$"
   155  	p := Pair{&i, &j}
   156  	param3(&p)
   157  	sink = p // ERROR "p escapes to heap$"
   158  }
   159  
   160  // in -> rcvr
   161  func (p *Pair) param4(i *int) { // ERROR "p does not escape$" "leaking param: i$"
   162  	p.p1 = i
   163  }
   164  
   165  func caller4a() {
   166  	i := 0 // ERROR "moved to heap: i$"
   167  	p := Pair{}
   168  	p.param4(&i)
   169  	_ = p
   170  }
   171  
   172  func caller4b() {
   173  	i := 0 // ERROR "moved to heap: i$"
   174  	p := Pair{}
   175  	p.param4(&i)
   176  	sink = p // ERROR "p escapes to heap$"
   177  }
   178  
   179  // in -> heap
   180  func param5(i *int) { // ERROR "leaking param: i$"
   181  	sink = i
   182  }
   183  
   184  func caller5() {
   185  	i := 0 // ERROR "moved to heap: i$"
   186  	param5(&i)
   187  }
   188  
   189  // *in -> heap
   190  func param6(i ***int) { // ERROR "leaking param content: i$"
   191  	sink = *i
   192  }
   193  
   194  func caller6a() {
   195  	i := 0  // ERROR "moved to heap: i$"
   196  	p := &i // ERROR "moved to heap: p$"
   197  	p2 := &p
   198  	param6(&p2)
   199  }
   200  
   201  // **in -> heap
   202  func param7(i ***int) { // ERROR "leaking param content: i$"
   203  	sink = **i
   204  }
   205  
   206  func caller7() {
   207  	i := 0 // ERROR "moved to heap: i$"
   208  	p := &i
   209  	p2 := &p
   210  	param7(&p2)
   211  }
   212  
   213  // **in -> heap
   214  func param8(i **int) { // ERROR "i does not escape$"
   215  	sink = **i // ERROR "\*\(\*i\) escapes to heap"
   216  }
   217  
   218  func caller8() {
   219  	i := 0
   220  	p := &i
   221  	param8(&p)
   222  }
   223  
   224  // *in -> out
   225  func param9(p ***int) **int { // ERROR "leaking param: p to result ~r0 level=1"
   226  	return *p
   227  }
   228  
   229  func caller9a() {
   230  	i := 0
   231  	p := &i
   232  	p2 := &p
   233  	_ = param9(&p2)
   234  }
   235  
   236  func caller9b() {
   237  	i := 0  // ERROR "moved to heap: i$"
   238  	p := &i // ERROR "moved to heap: p$"
   239  	p2 := &p
   240  	sink = param9(&p2)
   241  }
   242  
   243  // **in -> out
   244  func param10(p ***int) *int { // ERROR "leaking param: p to result ~r0 level=2"
   245  	return **p
   246  }
   247  
   248  func caller10a() {
   249  	i := 0
   250  	p := &i
   251  	p2 := &p
   252  	_ = param10(&p2)
   253  }
   254  
   255  func caller10b() {
   256  	i := 0 // ERROR "moved to heap: i$"
   257  	p := &i
   258  	p2 := &p
   259  	sink = param10(&p2)
   260  }
   261  
   262  // in escapes to heap (address of param taken and returned)
   263  func param11(i **int) ***int { // ERROR "moved to heap: i$"
   264  	return &i
   265  }
   266  
   267  func caller11a() {
   268  	i := 0  // ERROR "moved to heap: i"
   269  	p := &i // ERROR "moved to heap: p"
   270  	_ = param11(&p)
   271  }
   272  
   273  func caller11b() {
   274  	i := 0  // ERROR "moved to heap: i$"
   275  	p := &i // ERROR "moved to heap: p$"
   276  	sink = param11(&p)
   277  }
   278  
   279  func caller11c() { // GOOD
   280  	i := 0  // ERROR "moved to heap: i$"
   281  	p := &i // ERROR "moved to heap: p"
   282  	sink = *param11(&p)
   283  }
   284  
   285  func caller11d() {
   286  	i := 0  // ERROR "moved to heap: i$"
   287  	p := &i // ERROR "moved to heap: p"
   288  	p2 := &p
   289  	sink = param11(p2)
   290  }
   291  
   292  // &in -> rcvr
   293  type Indir struct {
   294  	p ***int
   295  }
   296  
   297  func (r *Indir) param12(i **int) { // ERROR "r does not escape$" "moved to heap: i$"
   298  	r.p = &i
   299  }
   300  
   301  func caller12a() {
   302  	i := 0  // ERROR "moved to heap: i$"
   303  	p := &i // ERROR "moved to heap: p$"
   304  	var r Indir
   305  	r.param12(&p)
   306  	_ = r
   307  }
   308  
   309  func caller12b() {
   310  	i := 0        // ERROR "moved to heap: i$"
   311  	p := &i       // ERROR "moved to heap: p$"
   312  	r := &Indir{} // ERROR "&Indir{} does not escape$"
   313  	r.param12(&p)
   314  	_ = r
   315  }
   316  
   317  func caller12c() {
   318  	i := 0  // ERROR "moved to heap: i$"
   319  	p := &i // ERROR "moved to heap: p$"
   320  	r := Indir{}
   321  	r.param12(&p)
   322  	sink = r
   323  }
   324  
   325  func caller12d() {
   326  	i := 0  // ERROR "moved to heap: i$"
   327  	p := &i // ERROR "moved to heap: p$"
   328  	r := Indir{}
   329  	r.param12(&p)
   330  	sink = **r.p
   331  }
   332  
   333  // in -> value rcvr
   334  type Val struct {
   335  	p **int
   336  }
   337  
   338  func (v Val) param13(i *int) { // ERROR "v does not escape$" "leaking param: i$"
   339  	*v.p = i
   340  }
   341  
   342  func caller13a() {
   343  	i := 0 // ERROR "moved to heap: i$"
   344  	var p *int
   345  	var v Val
   346  	v.p = &p
   347  	v.param13(&i)
   348  	_ = v
   349  }
   350  
   351  func caller13b() {
   352  	i := 0 // ERROR "moved to heap: i$"
   353  	var p *int
   354  	v := Val{&p}
   355  	v.param13(&i)
   356  	_ = v
   357  }
   358  
   359  func caller13c() {
   360  	i := 0 // ERROR "moved to heap: i$"
   361  	var p *int
   362  	v := &Val{&p} // ERROR "&Val{...} does not escape$"
   363  	v.param13(&i)
   364  	_ = v
   365  }
   366  
   367  func caller13d() {
   368  	i := 0     // ERROR "moved to heap: i$"
   369  	var p *int // ERROR "moved to heap: p$"
   370  	var v Val
   371  	v.p = &p
   372  	v.param13(&i)
   373  	sink = v
   374  }
   375  
   376  func caller13e() {
   377  	i := 0     // ERROR "moved to heap: i$"
   378  	var p *int // ERROR "moved to heap: p$"
   379  	v := Val{&p}
   380  	v.param13(&i)
   381  	sink = v
   382  }
   383  
   384  func caller13f() {
   385  	i := 0        // ERROR "moved to heap: i$"
   386  	var p *int    // ERROR "moved to heap: p$"
   387  	v := &Val{&p} // ERROR "&Val{...} escapes to heap$"
   388  	v.param13(&i)
   389  	sink = v
   390  }
   391  
   392  func caller13g() {
   393  	i := 0 // ERROR "moved to heap: i$"
   394  	var p *int
   395  	v := Val{&p}
   396  	v.param13(&i)
   397  	sink = *v.p
   398  }
   399  
   400  func caller13h() {
   401  	i := 0 // ERROR "moved to heap: i$"
   402  	var p *int
   403  	v := &Val{&p} // ERROR "&Val{...} does not escape$"
   404  	v.param13(&i)
   405  	sink = **v.p // ERROR "\*\(\*v\.p\) escapes to heap"
   406  }
   407  
   408  type Node struct {
   409  	p *Node
   410  }
   411  
   412  var Sink *Node
   413  
   414  func f(x *Node) { // ERROR "leaking param content: x"
   415  	Sink = &Node{x.p} // ERROR "&Node{...} escapes to heap"
   416  }
   417  
   418  func g(x *Node) *Node { // ERROR "leaking param content: x"
   419  	return &Node{x.p} // ERROR "&Node{...} escapes to heap"
   420  }
   421  
   422  func h(x *Node) { // ERROR "leaking param: x"
   423  	y := &Node{x} // ERROR "&Node{...} does not escape"
   424  	Sink = g(y)
   425  	f(y)
   426  }
   427  
   428  // interface(in) -> out
   429  // See also issue 29353.
   430  
   431  // Convert to a non-direct interface, require an allocation and
   432  // copy x to heap (not to result).
   433  func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$"
   434  	return x // ERROR "x escapes to heap"
   435  }
   436  
   437  // Convert to a direct interface, does not need an allocation.
   438  // So x only leaks to result.
   439  func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r0 level=0"
   440  	return x
   441  }
   442  

View as plain text