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
5package main
6
7import (
8	"runtime"
9	"testing"
10	"unsafe"
11)
12
13// global pointer slot
14var a *[8]uint
15
16// unfoldable true
17var 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.
25func 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.
61func 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
98func 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
111func 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
124func 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}
131func 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
141func TestUnsafe(t *testing.T) {
142	testf(t)
143	testg(t)
144	testdse(t)
145}
146