Source file test/escape_reflect.go

     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  
     9  package escape
    10  
    11  import (
    12  	"reflect"
    13  	"unsafe"
    14  )
    15  
    16  var sink interface{}
    17  
    18  func typ(x int) any {
    19  	v := reflect.ValueOf(x) // ERROR "x does not escape"
    20  	return v.Type()
    21  }
    22  
    23  func kind(x int) reflect.Kind {
    24  	v := reflect.ValueOf(x) // ERROR "x does not escape"
    25  	return v.Kind()
    26  }
    27  
    28  func int1(x int) int {
    29  	v := reflect.ValueOf(x) // ERROR "x does not escape"
    30  	return int(v.Int())
    31  }
    32  
    33  func 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  
    38  func 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.
    44  func bytes2(x []byte) []byte { // ERROR "leaking param: x$"
    45  	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
    46  	return v.Bytes()
    47  }
    48  
    49  func 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  
    54  func 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.
    60  func interface1(x any) any { // ERROR "leaking param: x$"
    61  	v := reflect.ValueOf(x)
    62  	return v.Interface()
    63  }
    64  
    65  func 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.
    71  func 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.
    77  func interface4(x *int) any { // ERROR "leaking param: x$"
    78  	v := reflect.ValueOf(x)
    79  	return v.Interface()
    80  }
    81  
    82  func 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.
    88  func uintptr1(x *int) uintptr { // ERROR "leaking param: x$"
    89  	v := reflect.ValueOf(x)
    90  	return v.Pointer()
    91  }
    92  
    93  func unsafeaddr(x *int) uintptr { // ERROR "leaking param: x$"
    94  	v := reflect.ValueOf(x).Elem()
    95  	return v.UnsafeAddr()
    96  }
    97  
    98  func ifacedata(x any) [2]uintptr { // ERROR "moved to heap: x"
    99  	v := reflect.ValueOf(&x).Elem()
   100  	return v.InterfaceData()
   101  }
   102  
   103  func 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  
   108  func is(x int) bool {
   109  	v := reflect.ValueOf(x) // ERROR "x does not escape"
   110  	return v.IsValid() || v.IsNil() || v.IsZero()
   111  }
   112  
   113  func 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  
   118  func 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  
   123  func overflow(x int) bool {
   124  	v := reflect.ValueOf(x) // ERROR "x does not escape"
   125  	return v.OverflowInt(1 << 62)
   126  }
   127  
   128  func 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  
   133  func len2(x [3]int) int {
   134  	v := reflect.ValueOf(x) // ERROR "x does not escape"
   135  	return v.Len()
   136  }
   137  
   138  func 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  
   143  func len4(x map[int]int) int { // ERROR "x does not escape"
   144  	v := reflect.ValueOf(x)
   145  	return v.Len()
   146  }
   147  
   148  func len5(x chan int) int { // ERROR "x does not escape"
   149  	v := reflect.ValueOf(x)
   150  	return v.Len()
   151  }
   152  
   153  func 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  
   158  func cap2(x [3]int) int {
   159  	v := reflect.ValueOf(x) // ERROR "x does not escape"
   160  	return v.Cap()
   161  }
   162  
   163  func cap3(x chan int) int { // ERROR "x does not escape"
   164  	v := reflect.ValueOf(x)
   165  	return v.Cap()
   166  }
   167  
   168  func setlen(x *[]int, n int) { // ERROR "x does not escape"
   169  	v := reflect.ValueOf(x).Elem()
   170  	v.SetLen(n)
   171  }
   172  
   173  func 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.
   179  func 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.
   185  func 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  
   190  func slice3(x [10]byte) []byte {
   191  	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
   192  	return v.Slice(1, 2).Bytes()
   193  }
   194  
   195  func elem1(x *int) int { // ERROR "x does not escape"
   196  	v := reflect.ValueOf(x)
   197  	return int(v.Elem().Int())
   198  }
   199  
   200  func 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  
   205  type S struct {
   206  	A int
   207  	B *int
   208  	C string
   209  }
   210  
   211  func (S) M() {}
   212  
   213  func 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  
   218  func 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  
   223  func 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  
   228  func 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)
   234  func 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  
   239  func index3(x [3]int) int {
   240  	v := reflect.ValueOf(x) // ERROR "x does not escape"
   241  	return int(v.Index(0).Int())
   242  }
   243  
   244  func 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  
   249  func 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.
   255  func 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  
   261  func 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  
   267  func 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  
   272  func 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.
   278  func 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  
   284  func mapkeys(m map[string]string) []reflect.Value { // ERROR "m does not escape"
   285  	mv := reflect.ValueOf(m)
   286  	return mv.MapKeys()
   287  }
   288  
   289  func mapiter1(m map[string]string) *reflect.MapIter { // ERROR "leaking param: m$"
   290  	mv := reflect.ValueOf(m)
   291  	return mv.MapRange()
   292  }
   293  
   294  func 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  
   303  func 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  
   308  func 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  
   314  func 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.
   321  func 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.
   328  func 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  
   334  func close1(ch chan string) { // ERROR "ch does not escape"
   335  	v := reflect.ValueOf(ch)
   336  	v.Close()
   337  }
   338  
   339  func 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.
   347  func 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  
   354  var (
   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.
   362  func 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.
   368  func 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.
   374  func 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.
   380  func 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  
   388  func set3(v reflect.Value, x int) { // ERROR "v does not escape"
   389  	v.SetInt(int64(x))
   390  }
   391  
   392  func 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  
   399  func set5(v reflect.Value, x string) { // ERROR "v does not escape" "leaking param: x$"
   400  	v.SetString(x)
   401  }
   402  
   403  func set6(v reflect.Value, x []byte) { // ERROR "v does not escape" "leaking param: x$"
   404  	v.SetBytes(x)
   405  }
   406  
   407  func set7(v reflect.Value, x unsafe.Pointer) { // ERROR "v does not escape" "leaking param: x$"
   408  	v.SetPointer(x)
   409  }
   410  
   411  func 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.
   419  func 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.
   426  func 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.
   431  func 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.
   437  func 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.
   442  func 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.
   449  func 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.
   457  func 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  

View as plain text