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_param1 checks *struct function parameters with similar tests. 9 10package notmain 11 12var Ssink *string 13 14type U struct { 15 _sp *string 16 _spp **string 17} 18 19type V struct { 20 _u U 21 _up *U 22 _upp **U 23} 24 25func (u U) SP() *string { // ERROR "leaking param: u to result ~r0 level=0$" 26 return u._sp 27} 28 29func (u U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=0$" 30 return u._spp 31} 32 33func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$" 34 return *u._spp 35} 36 37func tSPPi() { 38 s := "cat" // ERROR "moved to heap: s$" 39 ps := &s 40 pps := &ps 41 pu := &U{ps, pps} // ERROR "&U{...} does not escape$" 42 Ssink = pu.SPPi() 43} 44 45func tiSPP() { 46 s := "cat" // ERROR "moved to heap: s$" 47 ps := &s 48 pps := &ps 49 pu := &U{ps, pps} // ERROR "&U{...} does not escape$" 50 Ssink = *pu.SPP() 51} 52 53// BAD: need fine-grained analysis to avoid spurious escape of ps 54func tSP() { 55 s := "cat" // ERROR "moved to heap: s$" 56 ps := &s // ERROR "moved to heap: ps$" 57 pps := &ps 58 pu := &U{ps, pps} // ERROR "&U{...} does not escape$" 59 Ssink = pu.SP() 60} 61 62func (v V) u() U { // ERROR "leaking param: v to result ~r0 level=0$" 63 return v._u 64} 65 66func (v V) UP() *U { // ERROR "leaking param: v to result ~r0 level=0$" 67 return v._up 68} 69 70func (v V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=0$" 71 return v._upp 72} 73 74func (v V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=1$" 75 return *v._upp 76} 77 78func (v V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=1$" 79 return *v.UPP() 80} 81 82func (v V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=0$" 83 return v._u._sp 84} 85 86func (v V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=0$" 87 return v.u()._sp 88} 89 90func (v V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=1$" 91 return *v._u._spp 92} 93 94func (v V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=1$" 95 return v._u.SPPi() 96} 97 98func (v V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=1$" 99 return v._up._sp 100} 101 102func (v V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=1$" 103 return v._up.SP() 104} 105 106func (v V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=1$" 107 return v.UP()._sp 108} 109 110func (v V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=1$" 111 return v.UP().SP() 112} 113 114// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 115func 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 123 ps4 := &s4 // ERROR "moved to heap: ps4$" 124 ps6 := &s6 // ERROR "moved to heap: ps6$" 125 u1 := U{&s1, &ps2} 126 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 127 u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" 128 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 133func 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 141 ps4 := &s4 // ERROR "moved to heap: ps4$" 142 ps6 := &s6 // ERROR "moved to heap: ps6$" 143 u1 := U{&s1, &ps2} 144 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 145 u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" 146 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 151func 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 159 ps4 := &s4 // ERROR "moved to heap: ps4$" 160 ps6 := &s6 // ERROR "moved to heap: ps6$" 161 u1 := U{&s1, &ps2} 162 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 163 u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" 164 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 169func 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 177 ps4 := &s4 // ERROR "moved to heap: ps4$" 178 ps6 := &s6 // ERROR "moved to heap: ps6$" 179 u1 := U{&s1, &ps2} 180 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 181 u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" 182 v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" 183 Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) 184} 185 186func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$" 187 return *v._up._spp 188} 189 190func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$" 191 return v._up.SPPi() 192} 193 194func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$" 195 return *v.UP()._spp 196} 197 198func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$" 199 return v.UP().SPPi() 200} 201 202// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4 203func 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 211 ps4 := &s4 212 ps6 := &s6 // ERROR "moved to heap: ps6$" 213 u1 := U{&s1, &ps2} 214 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 215 u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" 216 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 221func 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 229 ps4 := &s4 230 ps6 := &s6 // ERROR "moved to heap: ps6$" 231 u1 := U{&s1, &ps2} 232 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 233 u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" 234 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 239func 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 247 ps4 := &s4 248 ps6 := &s6 // ERROR "moved to heap: ps6$" 249 u1 := U{&s1, &ps2} 250 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 251 u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" 252 v := &V{u1, u2, &u3} // ERROR "&V{...} 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 257func 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 265 ps4 := &s4 266 ps6 := &s6 // ERROR "moved to heap: ps6$" 267 u1 := U{&s1, &ps2} 268 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 269 u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" 270 v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" 271 Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) 272} 273 274func (v V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=3$" 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. 283func tUPPiSPPia() { // This test is sensitive to the level cap in function summary results. 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 291 ps4 := &s4 292 ps6 := &s6 293 u1 := U{&s1, &ps2} 294 u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" 295 u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" 296 v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" 297 Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) 298} 299