| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "runtime" |
| "testing" |
| "unsafe" |
| ) |
| |
| // global pointer slot |
| var a *[8]uint |
| |
| // unfoldable true |
| var always = true |
| |
| // Test to make sure that a pointer value which is alive |
| // across a call is retained, even when there are matching |
| // conversions to/from uintptr around the call. |
| // We arrange things very carefully to have to/from |
| // conversions on either side of the call which cannot be |
| // combined with any other conversions. |
| func f_ssa() *[8]uint { |
| // Make x a uintptr pointing to where a points. |
| var x uintptr |
| if always { |
| x = uintptr(unsafe.Pointer(a)) |
| } else { |
| x = 0 |
| } |
| // Clobber the global pointer. The only live ref |
| // to the allocated object is now x. |
| a = nil |
| |
| // Convert to pointer so it should hold |
| // the object live across GC call. |
| p := unsafe.Pointer(x) |
| |
| // Call gc. |
| runtime.GC() |
| |
| // Convert back to uintptr. |
| y := uintptr(p) |
| |
| // Mess with y so that the subsequent cast |
| // to unsafe.Pointer can't be combined with the |
| // uintptr cast above. |
| var z uintptr |
| if always { |
| z = y |
| } else { |
| z = 0 |
| } |
| return (*[8]uint)(unsafe.Pointer(z)) |
| } |
| |
| // g_ssa is the same as f_ssa, but with a bit of pointer |
| // arithmetic for added insanity. |
| func g_ssa() *[7]uint { |
| // Make x a uintptr pointing to where a points. |
| var x uintptr |
| if always { |
| x = uintptr(unsafe.Pointer(a)) |
| } else { |
| x = 0 |
| } |
| // Clobber the global pointer. The only live ref |
| // to the allocated object is now x. |
| a = nil |
| |
| // Offset x by one int. |
| x += unsafe.Sizeof(int(0)) |
| |
| // Convert to pointer so it should hold |
| // the object live across GC call. |
| p := unsafe.Pointer(x) |
| |
| // Call gc. |
| runtime.GC() |
| |
| // Convert back to uintptr. |
| y := uintptr(p) |
| |
| // Mess with y so that the subsequent cast |
| // to unsafe.Pointer can't be combined with the |
| // uintptr cast above. |
| var z uintptr |
| if always { |
| z = y |
| } else { |
| z = 0 |
| } |
| return (*[7]uint)(unsafe.Pointer(z)) |
| } |
| |
| func testf(t *testing.T) { |
| a = new([8]uint) |
| for i := 0; i < 8; i++ { |
| a[i] = 0xabcd |
| } |
| c := f_ssa() |
| for i := 0; i < 8; i++ { |
| if c[i] != 0xabcd { |
| t.Fatalf("%d:%x\n", i, c[i]) |
| } |
| } |
| } |
| |
| func testg(t *testing.T) { |
| a = new([8]uint) |
| for i := 0; i < 8; i++ { |
| a[i] = 0xabcd |
| } |
| c := g_ssa() |
| for i := 0; i < 7; i++ { |
| if c[i] != 0xabcd { |
| t.Fatalf("%d:%x\n", i, c[i]) |
| } |
| } |
| } |
| |
| func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 { |
| *ui32 = 0xffffffff |
| *ui64 = 0 // store |
| ret := *ui32 // load from same address, should be zero |
| *ui64 = 0xffffffffffffffff // store |
| return ret |
| } |
| func testdse(t *testing.T) { |
| x := int64(-1) |
| // construct two pointers that alias one another |
| ui64 := (*uint64)(unsafe.Pointer(&x)) |
| ui32 := (*uint32)(unsafe.Pointer(&x)) |
| if want, got := uint32(0), alias_ssa(ui64, ui32); got != want { |
| t.Fatalf("alias_ssa: wanted %d, got %d\n", want, got) |
| } |
| } |
| |
| func TestUnsafe(t *testing.T) { |
| testf(t) |
| testg(t) |
| testdse(t) |
| } |