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 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=0$" 26 return u._sp 27 } 28 29 func (u U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=0$" 30 return u._spp 31 } 32 33 func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$" 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 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=0$" 63 return v._u 64 } 65 66 func (v V) UP() *U { // ERROR "leaking param: v to result ~r0 level=0$" 67 return v._up 68 } 69 70 func (v V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=0$" 71 return v._upp 72 } 73 74 func (v V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=1$" 75 return *v._upp 76 } 77 78 func (v V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=1$" 79 return *v.UPP() 80 } 81 82 func (v V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=0$" 83 return v._u._sp 84 } 85 86 func (v V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=0$" 87 return v.u()._sp 88 } 89 90 func (v V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=1$" 91 return *v._u._spp 92 } 93 94 func (v V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=1$" 95 return v._u.SPPi() 96 } 97 98 func (v V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=1$" 99 return v._up._sp 100 } 101 102 func (v V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=1$" 103 return v._up.SP() 104 } 105 106 func (v V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=1$" 107 return v.UP()._sp 108 } 109 110 func (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 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 196 } 197 198 func (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 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=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. 283 func 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 // 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