Home | History | Annotate | Download | only in fixedbugs
      1 // run
      2 
      3 // Copyright 2016 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 // Previously, cmd/compile would rewrite
      8 //
      9 //     check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
     10 //
     11 // to
     12 //
     13 //     var autotmp_1 uintptr = testMeth(1).Pointer()
     14 //     var autotmp_2 uintptr = testMeth(2).Pointer()
     15 //     check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2))
     16 //
     17 // However, that means autotmp_1 is the only reference to the int
     18 // variable containing the value "1", but it's not a pointer type,
     19 // so it was at risk of being garbage collected by the evaluation of
     20 // testMeth(2).Pointer(), even though package unsafe's documentation
     21 // says the original code was allowed.
     22 //
     23 // Now cmd/compile rewrites it to
     24 //
     25 //     var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer())
     26 //     var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer())
     27 //     check(autotmp_1, autotmp_2)
     28 //
     29 // to ensure the pointed-to variables are visible to the GC.
     30 
     31 package main
     32 
     33 import (
     34 	"fmt"
     35 	"reflect"
     36 	"runtime"
     37 	"unsafe"
     38 )
     39 
     40 func main() {
     41 	// Test all the different ways we can invoke reflect.Value.Pointer.
     42 
     43 	// Direct method invocation.
     44 	check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
     45 
     46 	// Invocation via method expression.
     47 	check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2))))
     48 
     49 	// Invocation via interface.
     50 	check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer()))
     51 
     52 	// Invocation via method value.
     53 	check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)()))
     54 }
     55 
     56 func check(p, q unsafe.Pointer) {
     57 	a, b := *(*int)(p), *(*int)(q)
     58 	if a != 1 || b != 2 {
     59 		fmt.Printf("got %v, %v; expected 1, 2\n", a, b)
     60 	}
     61 }
     62 
     63 func testMeth(x int) reflect.Value {
     64 	// Force GC to run.
     65 	runtime.GC()
     66 	return reflect.ValueOf(&x)
     67 }
     68 
     69 type Pointerer interface {
     70 	Pointer() uintptr
     71 }
     72 
     73 func testInter(x int) Pointerer {
     74 	return testMeth(x)
     75 }
     76 
     77 func testFunc(x int) func() uintptr {
     78 	return testMeth(x).Pointer
     79 }
     80