github.com/google/capslock@v0.2.3-0.20240517042941-dac19fc347c0/testpkgs/usereflect/usereflect.go (about)

     1  // Copyright 2023 Google LLC
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file or at
     5  // https://developers.google.com/open-source/licenses/bsd
     6  
     7  // Package usereflect is used for testing.
     8  package usereflect
     9  
    10  import (
    11  	"encoding/json"
    12  	"math/rand"
    13  	"reflect"
    14  	"sync"
    15  	"unsafe"
    16  
    17  	"github.com/google/capslock/testpkgs/callnet"
    18  )
    19  
    20  // ValueSetFunc uses (reflect.Value).Set to change a func variable
    21  // to point to a different function, then calls it.
    22  func ValueSetFunc() int {
    23  	f := func() int { return 42 }
    24  	v1 := reflect.ValueOf(&f)
    25  	v2 := v1.Elem()
    26  	v3 := reflect.ValueOf(callnet.Foo)
    27  	v2.Set(v3)
    28  	return f()
    29  }
    30  
    31  // ValueSetInt uses (reflect.Value).Set to change an int.
    32  func ValueSetInt() int {
    33  	f := 123
    34  	g := 456
    35  	reflect.ValueOf(&f).Elem().Set(reflect.ValueOf(g))
    36  	return f
    37  }
    38  
    39  type fooer interface {
    40  	foo() int
    41  }
    42  
    43  type t1 int
    44  
    45  func (_ t1) foo() int { return 42 }
    46  
    47  type t2 int
    48  
    49  func (_ t2) foo() int { return callnet.Foo() + 1 }
    50  
    51  // ValueSetInterface uses (reflect.Value).Set to change an interface
    52  // variable to a value with a different concrete type.
    53  func ValueSetInterface() int {
    54  	var f fooer = t1(1)
    55  	var g fooer = t2(1)
    56  	reflect.ValueOf(&f).Elem().Set(reflect.ValueOf(g))
    57  	return f.foo()
    58  }
    59  
    60  // MakeFunc sets a func variable to an interesting function using MakeFunc and
    61  // (reflect.Value).Set.
    62  func MakeFunc() int {
    63  	f1 := func() int { return 42 }
    64  	f2 := func(_ []reflect.Value) []reflect.Value {
    65  		x := callnet.Foo() + 1
    66  		return []reflect.Value{reflect.ValueOf(x)}
    67  	}
    68  	v := reflect.MakeFunc(reflect.ValueOf(f1).Type(), f2)
    69  	reflect.ValueOf(&f1).Elem().Set(v)
    70  	return f1()
    71  }
    72  
    73  // TypeConfusionWithNewAt modifies a func pointer using reflect.NewAt and
    74  // (reflect.Value).Set.
    75  func TypeConfusionWithNewAt() int {
    76  	f := func() int { return 42 }
    77  	g := func() int { return callnet.Foo() + 1 }
    78  	fp := &f
    79  	v := reflect.NewAt(reflect.TypeOf(uintptr(0)), unsafe.Pointer(&fp)).Elem()
    80  	// v now has type uintptr, but refers to fp.
    81  	v.Set(reflect.ValueOf(uintptr(unsafe.Pointer(&g))))
    82  	return (*fp)()
    83  }
    84  
    85  // TypeConfusionWithNewAtTwo modifies a func pointer using reflect.NewAt and
    86  // (reflect.Value).Interface.
    87  func TypeConfusionWithNewAtTwo() int {
    88  	f := func() int { return 42 }
    89  	g := func() int { return callnet.Foo() + 1 }
    90  	fp := &f
    91  	v := reflect.NewAt(reflect.TypeOf(uintptr(0)), unsafe.Pointer(&fp)).Interface()
    92  	*v.(*uintptr) = uintptr(unsafe.Pointer(&g))
    93  	return (*fp)()
    94  }
    95  
    96  // TypeConfusionWithValueRace uses concurrent writes to a reflect.Value to
    97  // create a Value that refers to a func pointer but which has type uintptr.
    98  func TypeConfusionWithValueRace() int {
    99  	var (
   100  		fn               = func() int { return 42 }
   101  		goal             = callnet.Foo
   102  		fnp  *func() int = &fn
   103  		u    uintptr     = 12345
   104  		done             = false
   105  	)
   106  	for !done {
   107  		// v will contain reflect.Value variables each of which has type
   108  		// *uintptr or **func() int, pointing to u or fnp respectively.
   109  		// We start two goroutines which copy these values from one to another,
   110  		// trying to create a torn reflect.Value that has type *uintptr but which
   111  		// points to fnp.  Then we can write any uintptr to that Value using Set,
   112  		// making *fnp point to an arbitrary function (in this case, callnet.Foo).
   113  		var v [100]reflect.Value
   114  		for i := 0; i < 100; i = i + 2 {
   115  			v[i], v[i+1] = reflect.ValueOf(&u), reflect.ValueOf(&fnp)
   116  		}
   117  		var wg sync.WaitGroup
   118  		wg.Add(2)
   119  		go func() {
   120  			for i := 0; i < 1e7; i++ {
   121  				v[i%100] = v[(i+1)%100]
   122  			}
   123  			wg.Done()
   124  		}()
   125  		go func() {
   126  			for i := 0; i < 1e7; i++ {
   127  				v[i%100] = v[(i+12)%100]
   128  			}
   129  			wg.Done()
   130  		}()
   131  		wg.Wait()
   132  		for i := 0; i < 100; i++ {
   133  			v := v[i].Elem()
   134  			if v.Kind() != reflect.Uintptr {
   135  				continue
   136  			}
   137  			if v.Uint() == 12345 {
   138  				continue
   139  			}
   140  			done = true
   141  			v.SetUint(uint64(uintptr(unsafe.Pointer(&goal))))
   142  		}
   143  	}
   144  	return (*fnp)()
   145  }
   146  
   147  // ChangeSliceCapacityWithSliceHeader uses reflect.SliceHeader to directly
   148  // modify the capacity of a slice, in order to overwrite a func pointer.
   149  func ChangeSliceCapacityWithSliceHeader() int {
   150  	var (
   151  		fn   = func() int { return 42 }
   152  		goal = callnet.Foo
   153  		a    = make([]uintptr, 1)
   154  		b    = make([]*func() int, 1)
   155  		ah   = (*reflect.SliceHeader)(unsafe.Pointer(&a))
   156  		bh   = (*reflect.SliceHeader)(unsafe.Pointer(&b))
   157  	)
   158  	for bh.Data < ah.Data {
   159  		if rand.Intn(2) == 0 {
   160  			a = make([]uintptr, 1)
   161  		} else {
   162  			b = make([]*func() int, 1)
   163  		}
   164  	}
   165  	n := (bh.Data - ah.Data) / unsafe.Sizeof(a[0])
   166  	ah.Cap = int(n + 1)
   167  	ah.Len = int(n + 1)
   168  	b[0] = &fn
   169  	a[n] = uintptr(unsafe.Pointer(&goal))
   170  	return (*b[0])()
   171  }
   172  
   173  // ReadValue reads a number from a value using reflect.
   174  func ReadValue(x any) int {
   175  	v := reflect.ValueOf(x)
   176  	switch {
   177  	case v.CanUint():
   178  		return int(v.Uint())
   179  	case v.CanInt():
   180  		return int(v.Int())
   181  	case v.CanFloat():
   182  		return int(v.Float())
   183  	}
   184  	return 0
   185  }
   186  
   187  // JSONUnmarshal uses encoding/json to decode into a plain int.
   188  func JSONUnmarshal() int {
   189  	var x int
   190  	json.Unmarshal([]byte("42"), &x)
   191  	return x
   192  }
   193  
   194  type u int
   195  
   196  func (x *u) UnmarshalJSON([]byte) error {
   197  	*x = u(callnet.Foo() + 1)
   198  	return nil
   199  }
   200  
   201  // JSONUnmarshalTwo uses encoding/json to decode into a type that has
   202  // custom Unmarshal code.
   203  func JSONUnmarshalTwo() int {
   204  	var u u
   205  	json.Unmarshal([]byte("42"), &u)
   206  	return int(u)
   207  }
   208  
   209  var (
   210  	f                  func() int
   211  	g                  uintptr
   212  	globalValue1       = reflect.ValueOf(f)
   213  	globalValue2       = reflect.ValueOf(g)
   214  	globalValueStruct1 = rvs{42, reflect.ValueOf(f), 42}
   215  	globalValueStruct2 = rvs{42, reflect.ValueOf(g), 42}
   216  	valueSlice1        = []reflect.Value{reflect.ValueOf(f)}
   217  	valueSlice2        = []reflect.Value{reflect.ValueOf(g)}
   218  )
   219  
   220  // CopyValue copies a reflect.Value.
   221  func CopyValue() {
   222  	var f func() int
   223  	var g uintptr
   224  	v := reflect.ValueOf(f)
   225  	w := reflect.ValueOf(g)
   226  	v = w
   227  	_ = v
   228  }
   229  
   230  // CopyValueGlobal copies a reflect.Value that is not a local variable.
   231  func CopyValueGlobal() {
   232  	globalValue1 = globalValue2
   233  }
   234  
   235  // CopyValueConcurrently does concurrent copies to a reflect.Value.
   236  func CopyValueConcurrently() {
   237  	var f func() int
   238  	var g uintptr
   239  	var v reflect.Value
   240  	go func() {
   241  		v = reflect.ValueOf(f)
   242  	}()
   243  	go func() {
   244  		v = reflect.ValueOf(g)
   245  	}()
   246  	_ = v
   247  }
   248  
   249  // CopyValueViaPointer copies a reflect.Value via a pointer.
   250  func CopyValueViaPointer() {
   251  	var f func() int
   252  	var g uintptr
   253  	v := reflect.ValueOf(f)
   254  	w := reflect.ValueOf(g)
   255  	p := &v
   256  	*p = w
   257  	_ = v
   258  }
   259  
   260  type rv = reflect.Value
   261  
   262  // CopyValueEquivalent copies a value with a type equivalent to reflect.Value.
   263  func CopyValueEquivalent() {
   264  	var f func() int
   265  	var g uintptr
   266  	v := rv(reflect.ValueOf(f))
   267  	w := rv(reflect.ValueOf(g))
   268  	v = w
   269  	_ = v
   270  }
   271  
   272  // CopyValueEquivalentViaPointer copies a value with a type equivalent to reflect.Value
   273  // via a pointer.
   274  func CopyValueEquivalentViaPointer() {
   275  	var f func() int
   276  	var g uintptr
   277  	v := rv(reflect.ValueOf(f))
   278  	w := rv(reflect.ValueOf(g))
   279  	p := &v
   280  	*p = w
   281  	_ = v
   282  }
   283  
   284  // rvs is a struct that contains a field of type reflect.Value.
   285  type rvs struct {
   286  	x int
   287  	v reflect.Value
   288  	y float32
   289  }
   290  
   291  // CopyValueContainingStruct copies a struct containing a reflect.Value.
   292  func CopyValueContainingStruct() {
   293  	var f func() int
   294  	var g uintptr
   295  	v := rvs{42, reflect.ValueOf(f), 42}
   296  	w := rvs{42, reflect.ValueOf(g), 42}
   297  	v = w
   298  	_ = v
   299  }
   300  
   301  // CopyValueContainingStructViaPointer copies a struct containing a reflect.Value via a pointer.
   302  func CopyValueContainingStructViaPointer() {
   303  	var f func() int
   304  	var g uintptr
   305  	v := rvs{42, reflect.ValueOf(f), 42}
   306  	w := rvs{42, reflect.ValueOf(g), 42}
   307  	p := &v
   308  	*p = w
   309  	_ = v
   310  }
   311  
   312  // CopyValueInArray copies a reflect.Value in an array.
   313  func CopyValueInArray() {
   314  	var f func() int
   315  	var g uintptr
   316  	v := [1]reflect.Value{reflect.ValueOf(f)}
   317  	w := [1]reflect.Value{reflect.ValueOf(g)}
   318  	v = w
   319  	_ = v
   320  }
   321  
   322  // CopyValueInArrayViaPointer copies a reflect.Value in an array via a pointer.
   323  func CopyValueInArrayViaPointer() {
   324  	var f func() int
   325  	var g uintptr
   326  	v := [1]reflect.Value{reflect.ValueOf(f)}
   327  	w := [1]reflect.Value{reflect.ValueOf(g)}
   328  	p := &v
   329  	*p = w
   330  	_ = v
   331  }
   332  
   333  // CopyValueInMultipleAssignment copies a reflect.Value using an assignment of
   334  // multiple values.
   335  func CopyValueInMultipleAssignment() {
   336  	var f func() int
   337  	var g uintptr
   338  	v := reflect.ValueOf(f)
   339  	w := reflect.ValueOf(g)
   340  	var a, b, c, d int
   341  	a, v, b = c, w, d
   342  	_, _, _, _, _ = v, a, b, c, d
   343  }
   344  
   345  // CopyValueInMultipleAssignmentViaPointer copies a reflect.Value via a pointer
   346  // using an assignment of multiple values.
   347  func CopyValueInMultipleAssignmentViaPointer() {
   348  	var f func() int
   349  	var g uintptr
   350  	v := reflect.ValueOf(f)
   351  	w := reflect.ValueOf(g)
   352  	var a, b, c, d int
   353  	p := &v
   354  	a, *p, b = c, w, d
   355  	_, _, _, _, _ = v, a, b, c, d
   356  }
   357  
   358  // CopyValueInCommaOk copies a reflect.Value using a "comma-ok" assignment.
   359  func CopyValueInCommaOk() {
   360  	var f func() int
   361  	var g uintptr
   362  	v := reflect.ValueOf(f)
   363  	w := map[int]reflect.Value{1: reflect.ValueOf(g)}
   364  	var ok bool
   365  	v, ok = w[1]
   366  	_, _ = v, ok
   367  }
   368  
   369  // CopyValueInStructField copies a reflect.Value field in a struct.
   370  func CopyValueInStructField() {
   371  	var f func() int
   372  	var g uintptr
   373  	v := rvs{42, reflect.ValueOf(f), 42}
   374  	w := rvs{42, reflect.ValueOf(g), 42}
   375  	v.v = w.v
   376  	_ = v
   377  }
   378  
   379  // CopyValueInStructFieldViaPointer copies a reflect.Value field in a struct
   380  // via a pointer.
   381  func CopyValueInStructFieldViaPointer() {
   382  	var f func() int
   383  	var g uintptr
   384  	v := &rvs{42, reflect.ValueOf(f), 42}
   385  	w := rvs{42, reflect.ValueOf(g), 42}
   386  	v.v = w.v
   387  	_ = v
   388  }
   389  
   390  // RangeValue copies to a reflect.Value using a range clause.
   391  func RangeValue() {
   392  	var x reflect.Value
   393  	for _, x = range valueSlice1 {
   394  	}
   395  	for _, x = range valueSlice2 {
   396  	}
   397  	_ = x
   398  }
   399  
   400  // RangeValueTwo does concurrent copies to a reflect.Value using range clauses.
   401  func RangeValueTwo() {
   402  	var x reflect.Value
   403  	go func() {
   404  		for _, x = range valueSlice1 {
   405  		}
   406  	}()
   407  	go func() {
   408  		for _, x = range valueSlice2 {
   409  		}
   410  	}()
   411  	_ = x
   412  }