1// errorcheck -0 -m -l 2 3// Copyright 2022 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 reflect Value operations. 8 9package escape 10 11import ( 12 "reflect" 13 "unsafe" 14) 15 16var sink interface{} 17 18func typ(x int) any { 19 v := reflect.ValueOf(x) // ERROR "x does not escape" 20 return v.Type() 21} 22 23func kind(x int) reflect.Kind { 24 v := reflect.ValueOf(x) // ERROR "x does not escape" 25 return v.Kind() 26} 27 28func int1(x int) int { 29 v := reflect.ValueOf(x) // ERROR "x does not escape" 30 return int(v.Int()) 31} 32 33func ptr(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0" 34 v := reflect.ValueOf(x) 35 return (*int)(v.UnsafePointer()) 36} 37 38func bytes1(x []byte) byte { // ERROR "x does not escape" 39 v := reflect.ValueOf(x) // ERROR "x does not escape" 40 return v.Bytes()[0] 41} 42 43// Unfortunate: should only escape content. x (the interface storage) should not escape. 44func bytes2(x []byte) []byte { // ERROR "leaking param: x$" 45 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 46 return v.Bytes() 47} 48 49func string1(x string) string { // ERROR "leaking param: x to result ~r0 level=0" 50 v := reflect.ValueOf(x) // ERROR "x does not escape" 51 return v.String() 52} 53 54func string2(x int) string { 55 v := reflect.ValueOf(x) // ERROR "x does not escape" 56 return v.String() 57} 58 59// Unfortunate: should only escape to result. 60func interface1(x any) any { // ERROR "leaking param: x$" 61 v := reflect.ValueOf(x) 62 return v.Interface() 63} 64 65func interface2(x int) any { 66 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 67 return v.Interface() 68} 69 70// Unfortunate: should not escape. 71func interface3(x int) int { 72 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 73 return v.Interface().(int) 74} 75 76// Unfortunate: should only escape to result. 77func interface4(x *int) any { // ERROR "leaking param: x$" 78 v := reflect.ValueOf(x) 79 return v.Interface() 80} 81 82func addr(x *int) reflect.Value { // ERROR "leaking param: x to result ~r0 level=0" 83 v := reflect.ValueOf(x).Elem() 84 return v.Addr() 85} 86 87// functions returning pointer as uintptr have to escape. 88func uintptr1(x *int) uintptr { // ERROR "leaking param: x$" 89 v := reflect.ValueOf(x) 90 return v.Pointer() 91} 92 93func unsafeaddr(x *int) uintptr { // ERROR "leaking param: x$" 94 v := reflect.ValueOf(x).Elem() 95 return v.UnsafeAddr() 96} 97 98func ifacedata(x any) [2]uintptr { // ERROR "moved to heap: x" 99 v := reflect.ValueOf(&x).Elem() 100 return v.InterfaceData() 101} 102 103func can(x int) bool { 104 v := reflect.ValueOf(x) // ERROR "x does not escape" 105 return v.CanAddr() || v.CanInt() || v.CanSet() || v.CanInterface() 106} 107 108func is(x int) bool { 109 v := reflect.ValueOf(x) // ERROR "x does not escape" 110 return v.IsValid() || v.IsNil() || v.IsZero() 111} 112 113func is2(x [2]int) bool { 114 v := reflect.ValueOf(x) // ERROR "x does not escape" 115 return v.IsValid() || v.IsNil() || v.IsZero() 116} 117 118func is3(x struct{ a, b int }) bool { 119 v := reflect.ValueOf(x) // ERROR "x does not escape" 120 return v.IsValid() || v.IsNil() || v.IsZero() 121} 122 123func overflow(x int) bool { 124 v := reflect.ValueOf(x) // ERROR "x does not escape" 125 return v.OverflowInt(1 << 62) 126} 127 128func len1(x []int) int { // ERROR "x does not escape" 129 v := reflect.ValueOf(x) // ERROR "x does not escape" 130 return v.Len() 131} 132 133func len2(x [3]int) int { 134 v := reflect.ValueOf(x) // ERROR "x does not escape" 135 return v.Len() 136} 137 138func len3(x string) int { // ERROR "x does not escape" 139 v := reflect.ValueOf(x) // ERROR "x does not escape" 140 return v.Len() 141} 142 143func len4(x map[int]int) int { // ERROR "x does not escape" 144 v := reflect.ValueOf(x) 145 return v.Len() 146} 147 148func len5(x chan int) int { // ERROR "x does not escape" 149 v := reflect.ValueOf(x) 150 return v.Len() 151} 152 153func cap1(x []int) int { // ERROR "x does not escape" 154 v := reflect.ValueOf(x) // ERROR "x does not escape" 155 return v.Cap() 156} 157 158func cap2(x [3]int) int { 159 v := reflect.ValueOf(x) // ERROR "x does not escape" 160 return v.Cap() 161} 162 163func cap3(x chan int) int { // ERROR "x does not escape" 164 v := reflect.ValueOf(x) 165 return v.Cap() 166} 167 168func setlen(x *[]int, n int) { // ERROR "x does not escape" 169 v := reflect.ValueOf(x).Elem() 170 v.SetLen(n) 171} 172 173func setcap(x *[]int, n int) { // ERROR "x does not escape" 174 v := reflect.ValueOf(x).Elem() 175 v.SetCap(n) 176} 177 178// Unfortunate: x doesn't need to escape to heap, just to result. 179func slice1(x []byte) []byte { // ERROR "leaking param: x$" 180 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 181 return v.Slice(1, 2).Bytes() 182} 183 184// Unfortunate: x doesn't need to escape to heap, just to result. 185func slice2(x string) string { // ERROR "leaking param: x$" 186 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 187 return v.Slice(1, 2).String() 188} 189 190func slice3(x [10]byte) []byte { 191 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 192 return v.Slice(1, 2).Bytes() 193} 194 195func elem1(x *int) int { // ERROR "x does not escape" 196 v := reflect.ValueOf(x) 197 return int(v.Elem().Int()) 198} 199 200func elem2(x *string) string { // ERROR "leaking param: x to result ~r0 level=1" 201 v := reflect.ValueOf(x) 202 return string(v.Elem().String()) 203} 204 205type S struct { 206 A int 207 B *int 208 C string 209} 210 211func (S) M() {} 212 213func field1(x S) int { // ERROR "x does not escape" 214 v := reflect.ValueOf(x) // ERROR "x does not escape" 215 return int(v.Field(0).Int()) 216} 217 218func field2(x S) string { // ERROR "leaking param: x to result ~r0 level=0" 219 v := reflect.ValueOf(x) // ERROR "x does not escape" 220 return v.Field(2).String() 221} 222 223func numfield(x S) int { // ERROR "x does not escape" 224 v := reflect.ValueOf(x) // ERROR "x does not escape" 225 return v.NumField() 226} 227 228func index1(x []int) int { // ERROR "x does not escape" 229 v := reflect.ValueOf(x) // ERROR "x does not escape" 230 return int(v.Index(0).Int()) 231} 232 233// Unfortunate: should only leak content (level=1) 234func index2(x []string) string { // ERROR "leaking param: x to result ~r0 level=0" 235 v := reflect.ValueOf(x) // ERROR "x does not escape" 236 return v.Index(0).String() 237} 238 239func index3(x [3]int) int { 240 v := reflect.ValueOf(x) // ERROR "x does not escape" 241 return int(v.Index(0).Int()) 242} 243 244func index4(x [3]string) string { // ERROR "leaking param: x to result ~r0 level=0" 245 v := reflect.ValueOf(x) // ERROR "x does not escape" 246 return v.Index(0).String() 247} 248 249func index5(x string) byte { // ERROR "x does not escape" 250 v := reflect.ValueOf(x) // ERROR "x does not escape" 251 return byte(v.Index(0).Uint()) 252} 253 254// Unfortunate: x (the interface storage) doesn't need to escape as the function takes a scalar arg. 255func call1(f func(int), x int) { // ERROR "leaking param: f$" 256 fv := reflect.ValueOf(f) 257 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 258 fv.Call([]reflect.Value{v}) // ERROR "\[\]reflect\.Value{\.\.\.} does not escape" 259} 260 261func call2(f func(*int), x *int) { // ERROR "leaking param: f$" "leaking param: x$" 262 fv := reflect.ValueOf(f) 263 v := reflect.ValueOf(x) 264 fv.Call([]reflect.Value{v}) // ERROR "\[\]reflect.Value{\.\.\.} does not escape" 265} 266 267func method(x S) reflect.Value { // ERROR "leaking param: x$" 268 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 269 return v.Method(0) 270} 271 272func nummethod(x S) int { // ERROR "x does not escape" 273 v := reflect.ValueOf(x) // ERROR "x does not escape" 274 return v.NumMethod() 275} 276 277// Unfortunate: k doesn't need to escape. 278func mapindex(m map[string]string, k string) string { // ERROR "m does not escape" "leaking param: k$" 279 mv := reflect.ValueOf(m) 280 kv := reflect.ValueOf(k) // ERROR "k escapes to heap" 281 return mv.MapIndex(kv).String() 282} 283 284func mapkeys(m map[string]string) []reflect.Value { // ERROR "m does not escape" 285 mv := reflect.ValueOf(m) 286 return mv.MapKeys() 287} 288 289func mapiter1(m map[string]string) *reflect.MapIter { // ERROR "leaking param: m$" 290 mv := reflect.ValueOf(m) 291 return mv.MapRange() 292} 293 294func mapiter2(m map[string]string) string { // ERROR "leaking param: m$" 295 mv := reflect.ValueOf(m) 296 it := mv.MapRange() 297 if it.Next() { 298 return it.Key().String() 299 } 300 return "" 301} 302 303func mapiter3(m map[string]string, it *reflect.MapIter) { // ERROR "leaking param: m$" "it does not escape" 304 mv := reflect.ValueOf(m) 305 it.Reset(mv) 306} 307 308func recv1(ch chan string) string { // ERROR "ch does not escape" 309 v := reflect.ValueOf(ch) 310 r, _ := v.Recv() 311 return r.String() 312} 313 314func recv2(ch chan string) string { // ERROR "ch does not escape" 315 v := reflect.ValueOf(ch) 316 r, _ := v.TryRecv() 317 return r.String() 318} 319 320// Unfortunate: x (the interface storage) doesn't need to escape. 321func send1(ch chan string, x string) { // ERROR "ch does not escape" "leaking param: x$" 322 vc := reflect.ValueOf(ch) 323 vx := reflect.ValueOf(x) // ERROR "x escapes to heap" 324 vc.Send(vx) 325} 326 327// Unfortunate: x (the interface storage) doesn't need to escape. 328func send2(ch chan string, x string) bool { // ERROR "ch does not escape" "leaking param: x$" 329 vc := reflect.ValueOf(ch) 330 vx := reflect.ValueOf(x) // ERROR "x escapes to heap" 331 return vc.TrySend(vx) 332} 333 334func close1(ch chan string) { // ERROR "ch does not escape" 335 v := reflect.ValueOf(ch) 336 v.Close() 337} 338 339func select1(ch chan string) string { // ERROR "leaking param: ch$" 340 v := reflect.ValueOf(ch) 341 cas := reflect.SelectCase{Dir: reflect.SelectRecv, Chan: v} 342 _, r, _ := reflect.Select([]reflect.SelectCase{cas}) // ERROR "\[\]reflect.SelectCase{...} does not escape" 343 return r.String() 344} 345 346// Unfortunate: x (the interface storage) doesn't need to escape. 347func select2(ch chan string, x string) { // ERROR "leaking param: ch$" "leaking param: x$" 348 vc := reflect.ValueOf(ch) 349 vx := reflect.ValueOf(x) // ERROR "x escapes to heap" 350 cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: vc, Send: vx} 351 reflect.Select([]reflect.SelectCase{cas}) // ERROR "\[\]reflect.SelectCase{...} does not escape" 352} 353 354var ( 355 intTyp = reflect.TypeOf(int(0)) // ERROR "0 does not escape" 356 uintTyp = reflect.TypeOf(uint(0)) // ERROR "uint\(0\) does not escape" 357 stringTyp = reflect.TypeOf(string("")) // ERROR ".. does not escape" 358 bytesTyp = reflect.TypeOf([]byte{}) // ERROR "\[\]byte{} does not escape" 359) 360 361// Unfortunate: should not escape. 362func convert1(x int) uint { 363 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 364 return uint(v.Convert(uintTyp).Uint()) 365} 366 367// Unfortunate: should only escape content to result. 368func convert2(x []byte) string { // ERROR "leaking param: x$" 369 v := reflect.ValueOf(x) // ERROR "x escapes to heap" 370 return v.Convert(stringTyp).String() 371} 372 373// Unfortunate: v doesn't need to leak, x (the interface storage) doesn't need to escape. 374func set1(v reflect.Value, x int) { // ERROR "leaking param: v$" 375 vx := reflect.ValueOf(x) // ERROR "x escapes to heap" 376 v.Set(vx) 377} 378 379// Unfortunate: a can be stack allocated, x (the interface storage) doesn't need to escape. 380func set2(x int) int64 { 381 var a int // ERROR "moved to heap: a" 382 v := reflect.ValueOf(&a).Elem() 383 vx := reflect.ValueOf(x) // ERROR "x escapes to heap" 384 v.Set(vx) 385 return v.Int() 386} 387 388func set3(v reflect.Value, x int) { // ERROR "v does not escape" 389 v.SetInt(int64(x)) 390} 391 392func set4(x int) int { 393 var a int 394 v := reflect.ValueOf(&a).Elem() // a should not escape, no error printed 395 v.SetInt(int64(x)) 396 return int(v.Int()) 397} 398 399func set5(v reflect.Value, x string) { // ERROR "v does not escape" "leaking param: x$" 400 v.SetString(x) 401} 402 403func set6(v reflect.Value, x []byte) { // ERROR "v does not escape" "leaking param: x$" 404 v.SetBytes(x) 405} 406 407func set7(v reflect.Value, x unsafe.Pointer) { // ERROR "v does not escape" "leaking param: x$" 408 v.SetPointer(x) 409} 410 411func setmapindex(m map[string]string, k, e string) { // ERROR "m does not escape" "leaking param: k$" "leaking param: e$" 412 mv := reflect.ValueOf(m) 413 kv := reflect.ValueOf(k) // ERROR "k escapes to heap" 414 ev := reflect.ValueOf(e) // ERROR "e escapes to heap" 415 mv.SetMapIndex(kv, ev) 416} 417 418// Unfortunate: k doesn't need to escape. 419func mapdelete(m map[string]string, k string) { // ERROR "m does not escape" "leaking param: k$" 420 mv := reflect.ValueOf(m) 421 kv := reflect.ValueOf(k) // ERROR "k escapes to heap" 422 mv.SetMapIndex(kv, reflect.Value{}) 423} 424 425// Unfortunate: v doesn't need to leak. 426func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape" 427 v.SetIterKey(it) 428} 429 430// Unfortunate: v doesn't need to leak. 431func setiterkey2(v reflect.Value, m map[string]string) { // ERROR "leaking param: v$" "leaking param: m$" 432 it := reflect.ValueOf(m).MapRange() 433 v.SetIterKey(it) 434} 435 436// Unfortunate: v doesn't need to leak. 437func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape" 438 v.SetIterValue(it) 439} 440 441// Unfortunate: v doesn't need to leak. 442func setitervalue2(v reflect.Value, m map[string]string) { // ERROR "leaking param: v$" "leaking param: m$" 443 it := reflect.ValueOf(m).MapRange() 444 v.SetIterValue(it) 445} 446 447// Unfortunate: s doesn't need escape, only leak to result. 448// And x (interface storage) doesn't need to escape. 449func append1(s []int, x int) []int { // ERROR "leaking param: s$" 450 sv := reflect.ValueOf(s) // ERROR "s escapes to heap" 451 xv := reflect.ValueOf(x) // ERROR "x escapes to heap" 452 rv := reflect.Append(sv, xv) // ERROR "... argument does not escape" 453 return rv.Interface().([]int) 454} 455 456// Unfortunate: s doesn't need escape, only leak to result. 457func append2(s, x []int) []int { // ERROR "leaking param: s$" "x does not escape" 458 sv := reflect.ValueOf(s) // ERROR "s escapes to heap" 459 xv := reflect.ValueOf(x) // ERROR "x does not escape" 460 rv := reflect.AppendSlice(sv, xv) 461 return rv.Interface().([]int) 462} 463