1// errorcheck -0 -m -l
2
3// Copyright 2015 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 escape analysis for function parameters.
8
9// In this test almost everything is BAD except the simplest cases
10// where input directly flows to output.
11
12package escape
13
14func zero() int { return 0 }
15
16var sink interface{}
17
18// in -> out
19func param0(p *int) *int { // ERROR "leaking param: p to result ~r0"
20	return p
21}
22
23func caller0a() {
24	i := 0
25	_ = param0(&i)
26}
27
28func caller0b() {
29	i := 0 // ERROR "moved to heap: i$"
30	sink = param0(&i)
31}
32
33// in, in -> out, out
34func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r0" "leaking param: p2 to result ~r1"
35	return p1, p2
36}
37
38func caller1() {
39	i := 0 // ERROR "moved to heap: i$"
40	j := 0
41	sink, _ = param1(&i, &j)
42}
43
44// in -> other in
45func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "p2 does not escape$"
46	*p2 = p1
47}
48
49func caller2a() {
50	i := 0 // ERROR "moved to heap: i$"
51	var p *int
52	param2(&i, &p)
53	_ = p
54}
55
56func caller2b() {
57	i := 0 // ERROR "moved to heap: i$"
58	var p *int
59	param2(&i, &p)
60	sink = p
61}
62
63func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape"
64	p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]"
65}
66
67func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p"
68	// Function call inside index disables self-assignment case to trigger.
69	p.pairs[zero()] = p.pairs[1]
70	p.pairs[zero()+1] = p.pairs[1]
71}
72
73type PairOfPairs struct {
74	pairs [2]*Pair
75}
76
77type BoxedPair struct {
78	pair *Pair
79}
80
81type WrappedPair struct {
82	pair Pair
83}
84
85func leakParam(x interface{}) { // ERROR "leaking param: x"
86	sink = x
87}
88
89func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box"
90	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
91	sink = box.pair.p2
92}
93
94func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box"
95	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
96	sink = box.pair
97}
98
99func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box"
100	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
101	leakParam(box.pair.p2)
102}
103
104func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box"
105	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
106	leakParam(box.pair)
107}
108
109func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape"
110	box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2"
111	leakParam(box2.pair.p2)
112}
113
114func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape"
115	box1.pair.p1 = box2.pair.p1
116}
117
118func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape"
119	p1.pairs[0] = p2.pairs[1]
120}
121
122func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape"
123	p1.pairs[0].p1 = p2.pairs[1].p1
124}
125
126func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape"
127	box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2"
128}
129
130func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape"
131	w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2"
132}
133
134// in -> in
135type Pair struct {
136	p1 *int
137	p2 *int
138}
139
140func param3(p *Pair) { // ERROR "p does not escape"
141	p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2"
142}
143
144func caller3a() {
145	i := 0
146	j := 0
147	p := Pair{&i, &j}
148	param3(&p)
149	_ = p
150}
151
152func caller3b() {
153	i := 0 // ERROR "moved to heap: i$"
154	j := 0 // ERROR "moved to heap: j$"
155	p := Pair{&i, &j}
156	param3(&p)
157	sink = p // ERROR "p escapes to heap$"
158}
159
160// in -> rcvr
161func (p *Pair) param4(i *int) { // ERROR "p does not escape$" "leaking param: i$"
162	p.p1 = i
163}
164
165func caller4a() {
166	i := 0 // ERROR "moved to heap: i$"
167	p := Pair{}
168	p.param4(&i)
169	_ = p
170}
171
172func caller4b() {
173	i := 0 // ERROR "moved to heap: i$"
174	p := Pair{}
175	p.param4(&i)
176	sink = p // ERROR "p escapes to heap$"
177}
178
179// in -> heap
180func param5(i *int) { // ERROR "leaking param: i$"
181	sink = i
182}
183
184func caller5() {
185	i := 0 // ERROR "moved to heap: i$"
186	param5(&i)
187}
188
189// *in -> heap
190func param6(i ***int) { // ERROR "leaking param content: i$"
191	sink = *i
192}
193
194func caller6a() {
195	i := 0  // ERROR "moved to heap: i$"
196	p := &i // ERROR "moved to heap: p$"
197	p2 := &p
198	param6(&p2)
199}
200
201// **in -> heap
202func param7(i ***int) { // ERROR "leaking param content: i$"
203	sink = **i
204}
205
206func caller7() {
207	i := 0 // ERROR "moved to heap: i$"
208	p := &i
209	p2 := &p
210	param7(&p2)
211}
212
213// **in -> heap
214func param8(i **int) { // ERROR "i does not escape$"
215	sink = **i // ERROR "\*\(\*i\) escapes to heap"
216}
217
218func caller8() {
219	i := 0
220	p := &i
221	param8(&p)
222}
223
224// *in -> out
225func param9(p ***int) **int { // ERROR "leaking param: p to result ~r0 level=1"
226	return *p
227}
228
229func caller9a() {
230	i := 0
231	p := &i
232	p2 := &p
233	_ = param9(&p2)
234}
235
236func caller9b() {
237	i := 0  // ERROR "moved to heap: i$"
238	p := &i // ERROR "moved to heap: p$"
239	p2 := &p
240	sink = param9(&p2)
241}
242
243// **in -> out
244func param10(p ***int) *int { // ERROR "leaking param: p to result ~r0 level=2"
245	return **p
246}
247
248func caller10a() {
249	i := 0
250	p := &i
251	p2 := &p
252	_ = param10(&p2)
253}
254
255func caller10b() {
256	i := 0 // ERROR "moved to heap: i$"
257	p := &i
258	p2 := &p
259	sink = param10(&p2)
260}
261
262// in escapes to heap (address of param taken and returned)
263func param11(i **int) ***int { // ERROR "moved to heap: i$"
264	return &i
265}
266
267func caller11a() {
268	i := 0  // ERROR "moved to heap: i"
269	p := &i // ERROR "moved to heap: p"
270	_ = param11(&p)
271}
272
273func caller11b() {
274	i := 0  // ERROR "moved to heap: i$"
275	p := &i // ERROR "moved to heap: p$"
276	sink = param11(&p)
277}
278
279func caller11c() { // GOOD
280	i := 0  // ERROR "moved to heap: i$"
281	p := &i // ERROR "moved to heap: p"
282	sink = *param11(&p)
283}
284
285func caller11d() {
286	i := 0  // ERROR "moved to heap: i$"
287	p := &i // ERROR "moved to heap: p"
288	p2 := &p
289	sink = param11(p2)
290}
291
292// &in -> rcvr
293type Indir struct {
294	p ***int
295}
296
297func (r *Indir) param12(i **int) { // ERROR "r does not escape$" "moved to heap: i$"
298	r.p = &i
299}
300
301func caller12a() {
302	i := 0  // ERROR "moved to heap: i$"
303	p := &i // ERROR "moved to heap: p$"
304	var r Indir
305	r.param12(&p)
306	_ = r
307}
308
309func caller12b() {
310	i := 0        // ERROR "moved to heap: i$"
311	p := &i       // ERROR "moved to heap: p$"
312	r := &Indir{} // ERROR "&Indir{} does not escape$"
313	r.param12(&p)
314	_ = r
315}
316
317func caller12c() {
318	i := 0  // ERROR "moved to heap: i$"
319	p := &i // ERROR "moved to heap: p$"
320	r := Indir{}
321	r.param12(&p)
322	sink = r
323}
324
325func caller12d() {
326	i := 0  // ERROR "moved to heap: i$"
327	p := &i // ERROR "moved to heap: p$"
328	r := Indir{}
329	r.param12(&p)
330	sink = **r.p
331}
332
333// in -> value rcvr
334type Val struct {
335	p **int
336}
337
338func (v Val) param13(i *int) { // ERROR "v does not escape$" "leaking param: i$"
339	*v.p = i
340}
341
342func caller13a() {
343	i := 0 // ERROR "moved to heap: i$"
344	var p *int
345	var v Val
346	v.p = &p
347	v.param13(&i)
348	_ = v
349}
350
351func caller13b() {
352	i := 0 // ERROR "moved to heap: i$"
353	var p *int
354	v := Val{&p}
355	v.param13(&i)
356	_ = v
357}
358
359func caller13c() {
360	i := 0 // ERROR "moved to heap: i$"
361	var p *int
362	v := &Val{&p} // ERROR "&Val{...} does not escape$"
363	v.param13(&i)
364	_ = v
365}
366
367func caller13d() {
368	i := 0     // ERROR "moved to heap: i$"
369	var p *int // ERROR "moved to heap: p$"
370	var v Val
371	v.p = &p
372	v.param13(&i)
373	sink = v
374}
375
376func caller13e() {
377	i := 0     // ERROR "moved to heap: i$"
378	var p *int // ERROR "moved to heap: p$"
379	v := Val{&p}
380	v.param13(&i)
381	sink = v
382}
383
384func caller13f() {
385	i := 0        // ERROR "moved to heap: i$"
386	var p *int    // ERROR "moved to heap: p$"
387	v := &Val{&p} // ERROR "&Val{...} escapes to heap$"
388	v.param13(&i)
389	sink = v
390}
391
392func caller13g() {
393	i := 0 // ERROR "moved to heap: i$"
394	var p *int
395	v := Val{&p}
396	v.param13(&i)
397	sink = *v.p
398}
399
400func caller13h() {
401	i := 0 // ERROR "moved to heap: i$"
402	var p *int
403	v := &Val{&p} // ERROR "&Val{...} does not escape$"
404	v.param13(&i)
405	sink = **v.p // ERROR "\*\(\*v\.p\) escapes to heap"
406}
407
408type Node struct {
409	p *Node
410}
411
412var Sink *Node
413
414func f(x *Node) { // ERROR "leaking param content: x"
415	Sink = &Node{x.p} // ERROR "&Node{...} escapes to heap"
416}
417
418func g(x *Node) *Node { // ERROR "leaking param content: x"
419	return &Node{x.p} // ERROR "&Node{...} escapes to heap"
420}
421
422func h(x *Node) { // ERROR "leaking param: x"
423	y := &Node{x} // ERROR "&Node{...} does not escape"
424	Sink = g(y)
425	f(y)
426}
427
428// interface(in) -> out
429// See also issue 29353.
430
431// Convert to a non-direct interface, require an allocation and
432// copy x to heap (not to result).
433func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$"
434	return x // ERROR "x escapes to heap"
435}
436
437// Convert to a direct interface, does not need an allocation.
438// So x only leaks to result.
439func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r0 level=0"
440	return x
441}
442