Source file test/fixedbugs/issue15329.go

     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  

View as plain text