1// errorcheck -0 -m -l
2
3// Copyright 2012 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// Test, using compiler diagnostic flags, that the escape analysis is working.
8// Compiles but does not run.  Inlining is disabled.
9
10package foo
11
12import (
13	"runtime"
14	"unsafe"
15)
16
17func noleak(p *int) int { // ERROR "p does not escape"
18	return *p
19}
20
21func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
22	return p
23}
24
25func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: p to result ~r1"
26	return p, p
27}
28
29func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r0" "leaking param: q to result ~r1"
30	return p, q
31}
32
33func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0"
34	return leaktoret22(q, p)
35}
36
37func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: q to result ~r0"
38	r, s := leaktoret22(q, p)
39	return r, s
40}
41
42func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
43	r, s = leaktoret22(q, p)
44	return
45}
46
47func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
48	r, s = leaktoret22(q, p)
49	return r, s
50}
51
52func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r"
53	rr, ss := leaktoret22(q, p)
54	return rr, ss
55}
56
57var gp *int
58
59func leaktosink(p *int) *int { // ERROR "leaking param: p"
60	gp = p
61	return p
62}
63
64func f1() {
65	var x int
66	p := noleak(&x)
67	_ = p
68}
69
70func f2() {
71	var x int
72	p := leaktoret(&x)
73	_ = p
74}
75
76func f3() {
77	var x int // ERROR "moved to heap: x"
78	p := leaktoret(&x)
79	gp = p
80}
81
82func f4() {
83	var x int // ERROR "moved to heap: x"
84	p, q := leaktoret2(&x)
85	gp = p
86	gp = q
87}
88
89func f5() {
90	var x int
91	leaktoret22(leaktoret2(&x))
92}
93
94func f6() {
95	var x int // ERROR "moved to heap: x"
96	px1, px2 := leaktoret22(leaktoret2(&x))
97	gp = px1
98	_ = px2
99}
100
101type T struct{ x int }
102
103func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result"
104	t.x += u
105	return t, true
106}
107
108func f7() *T {
109	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap"
110	return r
111}
112
113func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
114	return leakrecursive2(q, p)
115}
116
117func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q"
118	if *p > *q {
119		return leakrecursive1(q, p)
120	}
121	// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges.
122	return p, q
123}
124
125var global interface{}
126
127type T1 struct {
128	X *int
129}
130
131type T2 struct {
132	Y *T1
133}
134
135func f8(p *T1) (k T2) { // ERROR "leaking param: p$"
136	if p == nil {
137		k = T2{}
138		return
139	}
140
141	// should make p leak always
142	global = p
143	return T2{p}
144}
145
146func f9() {
147	var j T1 // ERROR "moved to heap: j"
148	f8(&j)
149}
150
151func f10() {
152	// These don't escape but are too big for the stack
153	var x [1 << 30]byte         // ERROR "moved to heap: x"
154	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1073741824\) escapes to heap"
155	_ = x[0] + y[0]
156}
157
158// Test for issue 19687 (passing to unnamed parameters does not escape).
159func f11(**int) {
160}
161func f12(_ **int) {
162}
163func f13() {
164	var x *int
165	f11(&x)
166	f12(&x)
167	runtime.KeepAlive(&x)
168}
169
170// Test for issue 24305 (passing to unnamed receivers does not escape).
171type U int
172
173func (*U) M()   {}
174func (_ *U) N() {}
175
176func fbad24305a() {
177	var u U
178	u.M()
179	u.N()
180}
181
182func fbad24305b() {
183	var u U
184	(*U).M(&u)
185	(*U).N(&u)
186}
187
188// Issue 24730: taking address in a loop causes unnecessary escape
189type T24730 struct {
190	x [64]byte
191}
192
193func (t *T24730) g() { // ERROR "t does not escape"
194	y := t.x[:]
195	for i := range t.x[:] {
196		y = t.x[:]
197		y[i] = 1
198	}
199
200	var z *byte
201	for i := range t.x[:] {
202		z = &t.x[i]
203		*z = 2
204	}
205}
206
207// Issue 15730: copy causes unnecessary escape
208
209var sink []byte
210var sink2 []int
211var sink3 []*int
212
213func f15730a(args ...interface{}) { // ERROR "args does not escape"
214	for _, arg := range args {
215		switch a := arg.(type) {
216		case string:
217			copy(sink, a)
218		}
219	}
220}
221
222func f15730b(args ...interface{}) { // ERROR "args does not escape"
223	for _, arg := range args {
224		switch a := arg.(type) {
225		case []int:
226			copy(sink2, a)
227		}
228	}
229}
230
231func f15730c(args ...interface{}) { // ERROR "leaking param content: args"
232	for _, arg := range args {
233		switch a := arg.(type) {
234		case []*int:
235			// copy pointerful data should cause escape
236			copy(sink3, a)
237		}
238	}
239}
240
241// Issue 29000: unnamed parameter is not handled correctly
242
243var sink4 interface{}
244var alwaysFalse = false
245
246func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
247	sink4 = x
248	if alwaysFalse {
249		g29000()
250	}
251}
252
253func g29000() {
254	x := 1
255	f29000(2, x) // ERROR "x escapes to heap"
256}
257
258// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an
259// unnecessary escape.
260
261var sink28369 uintptr
262
263func f28369(n int) int {
264	if n == 0 {
265		sink28369 = uintptr(unsafe.Pointer(&n))
266		return n
267	}
268
269	return 1 + f28369(n-1)
270}
271
272// Issue 44614: parameters that flow to a heap-allocated result
273// parameter must be recorded as a heap-flow rather than a
274// result-flow.
275
276// N.B., must match "leaking param: p",
277// but *not* "leaking param: p to result r level=0".
278func f(p *int) (r *int) { // ERROR "leaking param: p$" "moved to heap: r"
279	sink4 = &r
280	return p
281}
282