github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/test/testdata/unsafe_test.go (about) 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 "runtime" 9 "testing" 10 "unsafe" 11 ) 12 13 // global pointer slot 14 var a *[8]uint 15 16 // unfoldable true 17 var always = 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 always { 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 always { 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 always { 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 always { 91 z = y 92 } else { 93 z = 0 94 } 95 return (*[7]uint)(unsafe.Pointer(z)) 96 } 97 98 func testf(t *testing.T) { 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 t.Fatalf("%d:%x\n", i, c[i]) 107 } 108 } 109 } 110 111 func testg(t *testing.T) { 112 a = new([8]uint) 113 for i := 0; i < 8; i++ { 114 a[i] = 0xabcd 115 } 116 c := g_ssa() 117 for i := 0; i < 7; i++ { 118 if c[i] != 0xabcd { 119 t.Fatalf("%d:%x\n", i, c[i]) 120 } 121 } 122 } 123 124 func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 { 125 *ui32 = 0xffffffff 126 *ui64 = 0 // store 127 ret := *ui32 // load from same address, should be zero 128 *ui64 = 0xffffffffffffffff // store 129 return ret 130 } 131 func testdse(t *testing.T) { 132 x := int64(-1) 133 // construct two pointers that alias one another 134 ui64 := (*uint64)(unsafe.Pointer(&x)) 135 ui32 := (*uint32)(unsafe.Pointer(&x)) 136 if want, got := uint32(0), alias_ssa(ui64, ui32); got != want { 137 t.Fatalf("alias_ssa: wanted %d, got %d\n", want, got) 138 } 139 } 140 141 func TestUnsafe(t *testing.T) { 142 testf(t) 143 testg(t) 144 testdse(t) 145 }