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

View as plain text