Home | History | Annotate | Download | only in test
      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 *struct function parameters.
      8 // Note companion strict_param2 checks struct function parameters with similar tests.
      9 
     10 package notmain
     11 
     12 var Ssink *string
     13 
     14 type U struct {
     15 	_sp  *string
     16 	_spp **string
     17 }
     18 
     19 type V struct {
     20 	_u   U
     21 	_up  *U
     22 	_upp **U
     23 }
     24 
     25 func (u *U) SP() *string { // ERROR "leaking param: u to result ~r0 level=1$"
     26 	return u._sp
     27 }
     28 
     29 func (u *U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=1$"
     30 	return u._spp
     31 }
     32 
     33 func (u *U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=2$"
     34 	return *u._spp
     35 }
     36 
     37 func tSPPi() {
     38 	s := "cat"        // ERROR "moved to heap: s$"
     39 	ps := &s          // ERROR "&s escapes to heap$"
     40 	pps := &ps        // ERROR "tSPPi &ps does not escape$"
     41 	pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$"
     42 	Ssink = pu.SPPi()
     43 }
     44 
     45 func tiSPP() {
     46 	s := "cat"        // ERROR "moved to heap: s$"
     47 	ps := &s          // ERROR "&s escapes to heap$"
     48 	pps := &ps        // ERROR "tiSPP &ps does not escape$"
     49 	pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$"
     50 	Ssink = *pu.SPP()
     51 }
     52 
     53 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of ps
     54 func tSP() {
     55 	s := "cat"        // ERROR "moved to heap: s$"
     56 	ps := &s          // ERROR "&s escapes to heap$" "moved to heap: ps$"
     57 	pps := &ps        // ERROR "&ps escapes to heap$"
     58 	pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$"
     59 	Ssink = pu.SP()
     60 }
     61 
     62 func (v *V) u() U { // ERROR "leaking param: v to result ~r0 level=1$"
     63 	return v._u
     64 }
     65 
     66 func (v *V) UP() *U { // ERROR "leaking param: v to result ~r0 level=1$"
     67 	return v._up
     68 }
     69 
     70 func (v *V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=1$"
     71 	return v._upp
     72 }
     73 
     74 func (v *V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=2$"
     75 	return *v._upp
     76 }
     77 
     78 func (v *V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=2$"
     79 	return *v.UPP()
     80 }
     81 
     82 func (v *V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=1$"
     83 	return v._u._sp
     84 }
     85 
     86 func (v *V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=1$"
     87 	return v.u()._sp
     88 }
     89 
     90 func (v *V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
     91 	return *v._u._spp
     92 }
     93 
     94 func (v *V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
     95 	return v._u.SPPi() // ERROR "\(\*V\).USPPib v._u does not escape$"
     96 }
     97 
     98 func (v *V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=2$"
     99 	return v._up._sp
    100 }
    101 
    102 func (v *V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    103 	return v._up.SP()
    104 }
    105 
    106 func (v *V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    107 	return v.UP()._sp
    108 }
    109 
    110 func (v *V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    111 	return v.UP().SP()
    112 }
    113 
    114 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
    115 func tUPiSPa() {
    116 	s1 := "ant"
    117 	s2 := "bat"          // ERROR "moved to heap: s2$"
    118 	s3 := "cat"          // ERROR "moved to heap: s3$"
    119 	s4 := "dog"          // ERROR "moved to heap: s4$"
    120 	s5 := "emu"          // ERROR "moved to heap: s5$"
    121 	s6 := "fox"          // ERROR "moved to heap: s6$"
    122 	ps2 := &s2           // ERROR "&s2 escapes to heap$"
    123 	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
    124 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    125 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$"
    126 	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$"
    127 	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
    128 	v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$"
    129 	Ssink = v.UPiSPa()   // Ssink = &s3 (only &s3 really escapes)
    130 }
    131 
    132 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
    133 func tUPiSPb() {
    134 	s1 := "ant"
    135 	s2 := "bat"          // ERROR "moved to heap: s2$"
    136 	s3 := "cat"          // ERROR "moved to heap: s3$"
    137 	s4 := "dog"          // ERROR "moved to heap: s4$"
    138 	s5 := "emu"          // ERROR "moved to heap: s5$"
    139 	s6 := "fox"          // ERROR "moved to heap: s6$"
    140 	ps2 := &s2           // ERROR "&s2 escapes to heap$"
    141 	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
    142 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    143 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$"
    144 	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$"
    145 	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
    146 	v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$"
    147 	Ssink = v.UPiSPb()   // Ssink = &s3 (only &s3 really escapes)
    148 }
    149 
    150 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
    151 func tUPiSPc() {
    152 	s1 := "ant"
    153 	s2 := "bat"          // ERROR "moved to heap: s2$"
    154 	s3 := "cat"          // ERROR "moved to heap: s3$"
    155 	s4 := "dog"          // ERROR "moved to heap: s4$"
    156 	s5 := "emu"          // ERROR "moved to heap: s5$"
    157 	s6 := "fox"          // ERROR "moved to heap: s6$"
    158 	ps2 := &s2           // ERROR "&s2 escapes to heap$"
    159 	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
    160 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    161 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$"
    162 	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$"
    163 	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
    164 	v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$"
    165 	Ssink = v.UPiSPc()   // Ssink = &s3 (only &s3 really escapes)
    166 }
    167 
    168 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
    169 func tUPiSPd() {
    170 	s1 := "ant"
    171 	s2 := "bat"          // ERROR "moved to heap: s2$"
    172 	s3 := "cat"          // ERROR "moved to heap: s3$"
    173 	s4 := "dog"          // ERROR "moved to heap: s4$"
    174 	s5 := "emu"          // ERROR "moved to heap: s5$"
    175 	s6 := "fox"          // ERROR "moved to heap: s6$"
    176 	ps2 := &s2           // ERROR "&s2 escapes to heap$"
    177 	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
    178 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    179 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$"
    180 	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$"
    181 	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
    182 	v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$"
    183 	Ssink = v.UPiSPd()   // Ssink = &s3 (only &s3 really escapes)
    184 }
    185 
    186 func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    187 	return *v._up._spp
    188 }
    189 
    190 func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    191 	return v._up.SPPi()
    192 }
    193 
    194 func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    195 	return *v.UP()._spp // ERROR "V.UPiSPPic v does not escape$"
    196 }
    197 
    198 func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$"
    199 	return v.UP().SPPi() // ERROR "V.UPiSPPid v does not escape$"
    200 }
    201 
    202 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
    203 func tUPiSPPia() {
    204 	s1 := "ant"
    205 	s2 := "bat"
    206 	s3 := "cat"
    207 	s4 := "dog"          // ERROR "moved to heap: s4$"
    208 	s5 := "emu"          // ERROR "moved to heap: s5$"
    209 	s6 := "fox"          // ERROR "moved to heap: s6$"
    210 	ps2 := &s2           // ERROR "tUPiSPPia &s2 does not escape$"
    211 	ps4 := &s4           // ERROR "&s4 escapes to heap$"
    212 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    213 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$"
    214 	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$"
    215 	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$"
    216 	v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$"
    217 	Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
    218 }
    219 
    220 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
    221 func tUPiSPPib() {
    222 	s1 := "ant"
    223 	s2 := "bat"
    224 	s3 := "cat"
    225 	s4 := "dog"          // ERROR "moved to heap: s4$"
    226 	s5 := "emu"          // ERROR "moved to heap: s5$"
    227 	s6 := "fox"          // ERROR "moved to heap: s6$"
    228 	ps2 := &s2           // ERROR "tUPiSPPib &s2 does not escape$"
    229 	ps4 := &s4           // ERROR "&s4 escapes to heap$"
    230 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    231 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$"
    232 	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$"
    233 	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$"
    234 	v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$"
    235 	Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
    236 }
    237 
    238 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
    239 func tUPiSPPic() {
    240 	s1 := "ant"
    241 	s2 := "bat"
    242 	s3 := "cat"
    243 	s4 := "dog"          // ERROR "moved to heap: s4$"
    244 	s5 := "emu"          // ERROR "moved to heap: s5$"
    245 	s6 := "fox"          // ERROR "moved to heap: s6$"
    246 	ps2 := &s2           // ERROR "tUPiSPPic &s2 does not escape$"
    247 	ps4 := &s4           // ERROR "&s4 escapes to heap$"
    248 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    249 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$"
    250 	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$"
    251 	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$"
    252 	v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$"
    253 	Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
    254 }
    255 
    256 // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
    257 func tUPiSPPid() {
    258 	s1 := "ant"
    259 	s2 := "bat"
    260 	s3 := "cat"
    261 	s4 := "dog"          // ERROR "moved to heap: s4$"
    262 	s5 := "emu"          // ERROR "moved to heap: s5$"
    263 	s6 := "fox"          // ERROR "moved to heap: s6$"
    264 	ps2 := &s2           // ERROR "tUPiSPPid &s2 does not escape$"
    265 	ps4 := &s4           // ERROR "&s4 escapes to heap$"
    266 	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
    267 	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$"
    268 	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$"
    269 	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$"
    270 	v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$"
    271 	Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
    272 }
    273 
    274 func (v *V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=4$"
    275 	return *(*v._upp)._spp
    276 }
    277 
    278 // This test isolates the one value that needs to escape, not because
    279 // it distinguishes fields but because it knows that &s6 is the only
    280 // value reachable by two indirects from v.
    281 // The test depends on the level cap in the escape analysis tags
    282 // being able to encode that fact.
    283 func tUPPiSPPia() {
    284 	s1 := "ant"
    285 	s2 := "bat"
    286 	s3 := "cat"
    287 	s4 := "dog"
    288 	s5 := "emu"
    289 	s6 := "fox"           // ERROR "moved to heap: s6$"
    290 	ps2 := &s2            // ERROR "tUPPiSPPia &s2 does not escape$"
    291 	ps4 := &s4            // ERROR "tUPPiSPPia &s4 does not escape$"
    292 	ps6 := &s6            // ERROR "&s6 escapes to heap$"
    293 	u1 := U{&s1, &ps2}    // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$"
    294 	u2 := &U{&s3, &ps4}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$"
    295 	u3 := &U{&s5, &ps6}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$"
    296 	v := &V{u1, u2, &u3}  // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$"
    297 	Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes)
    298 }
    299