1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "runtime" 10 "unsafe" 11 ) 12 13 // global pointer slot 14 var a *[8]uint 15 16 // unfoldable true 17 var b = true 18 19 // Test to make sure that a pointer value which is alive 20 // across a call is retained, even when there are matching 21 // conversions to/from uintptr around the call. 22 // We arrange things very carefully to have to/from 23 // conversions on either side of the call which cannot be 24 // combined with any other conversions. 25 func f_ssa() *[8]uint { 26 // Make x a uintptr pointing to where a points. 27 var x uintptr 28 if b { 29 x = uintptr(unsafe.Pointer(a)) 30 } else { 31 x = 0 32 } 33 // Clobber the global pointer. The only live ref 34 // to the allocated object is now x. 35 a = nil 36 37 // Convert to pointer so it should hold 38 // the object live across GC call. 39 p := unsafe.Pointer(x) 40 41 // Call gc. 42 runtime.GC() 43 44 // Convert back to uintptr. 45 y := uintptr(p) 46 47 // Mess with y so that the subsequent cast 48 // to unsafe.Pointer can't be combined with the 49 // uintptr cast above. 50 var z uintptr 51 if b { 52 z = y 53 } else { 54 z = 0 55 } 56 return (*[8]uint)(unsafe.Pointer(z)) 57 } 58 59 // g_ssa is the same as f_ssa, but with a bit of pointer 60 // arithmetic for added insanity. 61 func g_ssa() *[7]uint { 62 // Make x a uintptr pointing to where a points. 63 var x uintptr 64 if b { 65 x = uintptr(unsafe.Pointer(a)) 66 } else { 67 x = 0 68 } 69 // Clobber the global pointer. The only live ref 70 // to the allocated object is now x. 71 a = nil 72 73 // Offset x by one int. 74 x += unsafe.Sizeof(int(0)) 75 76 // Convert to pointer so it should hold 77 // the object live across GC call. 78 p := unsafe.Pointer(x) 79 80 // Call gc. 81 runtime.GC() 82 83 // Convert back to uintptr. 84 y := uintptr(p) 85 86 // Mess with y so that the subsequent cast 87 // to unsafe.Pointer can't be combined with the 88 // uintptr cast above. 89 var z uintptr 90 if b { 91 z = y 92 } else { 93 z = 0 94 } 95 return (*[7]uint)(unsafe.Pointer(z)) 96 } 97 98 func testf() { 99 a = new([8]uint) 100 for i := 0; i < 8; i++ { 101 a[i] = 0xabcd 102 } 103 c := f_ssa() 104 for i := 0; i < 8; i++ { 105 if c[i] != 0xabcd { 106 fmt.Printf("%d:%x\n", i, c[i]) 107 panic("bad c") 108 } 109 } 110 } 111 112 func testg() { 113 a = new([8]uint) 114 for i := 0; i < 8; i++ { 115 a[i] = 0xabcd 116 } 117 c := g_ssa() 118 for i := 0; i < 7; i++ { 119 if c[i] != 0xabcd { 120 fmt.Printf("%d:%x\n", i, c[i]) 121 panic("bad c") 122 } 123 } 124 } 125 126 func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 { 127 *ui32 = 0xffffffff 128 *ui64 = 0 // store 129 ret := *ui32 // load from same address, should be zero 130 *ui64 = 0xffffffffffffffff // store 131 return ret 132 } 133 func testdse() { 134 x := int64(-1) 135 // construct two pointers that alias one another 136 ui64 := (*uint64)(unsafe.Pointer(&x)) 137 ui32 := (*uint32)(unsafe.Pointer(&x)) 138 if want, got := uint32(0), alias_ssa(ui64, ui32); got != want { 139 fmt.Printf("alias_ssa: wanted %d, got %d\n", want, got) 140 panic("alias_ssa") 141 } 142 } 143 144 func main() { 145 testf() 146 testg() 147 testdse() 148 } 149