1// errorcheck -0 -m -l
2
3// Copyright 2022 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 reflect Value operations.
8
9package escape
10
11import (
12	"reflect"
13	"unsafe"
14)
15
16var sink interface{}
17
18func typ(x int) any {
19	v := reflect.ValueOf(x) // ERROR "x does not escape"
20	return v.Type()
21}
22
23func kind(x int) reflect.Kind {
24	v := reflect.ValueOf(x) // ERROR "x does not escape"
25	return v.Kind()
26}
27
28func int1(x int) int {
29	v := reflect.ValueOf(x) // ERROR "x does not escape"
30	return int(v.Int())
31}
32
33func ptr(x *int) *int { // ERROR "leaking param: x to result ~r0 level=0"
34	v := reflect.ValueOf(x)
35	return (*int)(v.UnsafePointer())
36}
37
38func bytes1(x []byte) byte { // ERROR "x does not escape"
39	v := reflect.ValueOf(x) // ERROR "x does not escape"
40	return v.Bytes()[0]
41}
42
43// Unfortunate: should only escape content. x (the interface storage) should not escape.
44func bytes2(x []byte) []byte { // ERROR "leaking param: x$"
45	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
46	return v.Bytes()
47}
48
49func string1(x string) string { // ERROR "leaking param: x to result ~r0 level=0"
50	v := reflect.ValueOf(x) // ERROR "x does not escape"
51	return v.String()
52}
53
54func string2(x int) string {
55	v := reflect.ValueOf(x) // ERROR "x does not escape"
56	return v.String()
57}
58
59// Unfortunate: should only escape to result.
60func interface1(x any) any { // ERROR "leaking param: x$"
61	v := reflect.ValueOf(x)
62	return v.Interface()
63}
64
65func interface2(x int) any {
66	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
67	return v.Interface()
68}
69
70// Unfortunate: should not escape.
71func interface3(x int) int {
72	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
73	return v.Interface().(int)
74}
75
76// Unfortunate: should only escape to result.
77func interface4(x *int) any { // ERROR "leaking param: x$"
78	v := reflect.ValueOf(x)
79	return v.Interface()
80}
81
82func addr(x *int) reflect.Value { // ERROR "leaking param: x to result ~r0 level=0"
83	v := reflect.ValueOf(x).Elem()
84	return v.Addr()
85}
86
87// functions returning pointer as uintptr have to escape.
88func uintptr1(x *int) uintptr { // ERROR "leaking param: x$"
89	v := reflect.ValueOf(x)
90	return v.Pointer()
91}
92
93func unsafeaddr(x *int) uintptr { // ERROR "leaking param: x$"
94	v := reflect.ValueOf(x).Elem()
95	return v.UnsafeAddr()
96}
97
98func ifacedata(x any) [2]uintptr { // ERROR "moved to heap: x"
99	v := reflect.ValueOf(&x).Elem()
100	return v.InterfaceData()
101}
102
103func can(x int) bool {
104	v := reflect.ValueOf(x) // ERROR "x does not escape"
105	return v.CanAddr() || v.CanInt() || v.CanSet() || v.CanInterface()
106}
107
108func is(x int) bool {
109	v := reflect.ValueOf(x) // ERROR "x does not escape"
110	return v.IsValid() || v.IsNil() || v.IsZero()
111}
112
113func is2(x [2]int) bool {
114	v := reflect.ValueOf(x) // ERROR "x does not escape"
115	return v.IsValid() || v.IsNil() || v.IsZero()
116}
117
118func is3(x struct{ a, b int }) bool {
119	v := reflect.ValueOf(x) // ERROR "x does not escape"
120	return v.IsValid() || v.IsNil() || v.IsZero()
121}
122
123func overflow(x int) bool {
124	v := reflect.ValueOf(x) // ERROR "x does not escape"
125	return v.OverflowInt(1 << 62)
126}
127
128func len1(x []int) int { // ERROR "x does not escape"
129	v := reflect.ValueOf(x) // ERROR "x does not escape"
130	return v.Len()
131}
132
133func len2(x [3]int) int {
134	v := reflect.ValueOf(x) // ERROR "x does not escape"
135	return v.Len()
136}
137
138func len3(x string) int { // ERROR "x does not escape"
139	v := reflect.ValueOf(x) // ERROR "x does not escape"
140	return v.Len()
141}
142
143func len4(x map[int]int) int { // ERROR "x does not escape"
144	v := reflect.ValueOf(x)
145	return v.Len()
146}
147
148func len5(x chan int) int { // ERROR "x does not escape"
149	v := reflect.ValueOf(x)
150	return v.Len()
151}
152
153func cap1(x []int) int { // ERROR "x does not escape"
154	v := reflect.ValueOf(x) // ERROR "x does not escape"
155	return v.Cap()
156}
157
158func cap2(x [3]int) int {
159	v := reflect.ValueOf(x) // ERROR "x does not escape"
160	return v.Cap()
161}
162
163func cap3(x chan int) int { // ERROR "x does not escape"
164	v := reflect.ValueOf(x)
165	return v.Cap()
166}
167
168func setlen(x *[]int, n int) { // ERROR "x does not escape"
169	v := reflect.ValueOf(x).Elem()
170	v.SetLen(n)
171}
172
173func setcap(x *[]int, n int) { // ERROR "x does not escape"
174	v := reflect.ValueOf(x).Elem()
175	v.SetCap(n)
176}
177
178// Unfortunate: x doesn't need to escape to heap, just to result.
179func slice1(x []byte) []byte { // ERROR "leaking param: x$"
180	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
181	return v.Slice(1, 2).Bytes()
182}
183
184// Unfortunate: x doesn't need to escape to heap, just to result.
185func slice2(x string) string { // ERROR "leaking param: x$"
186	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
187	return v.Slice(1, 2).String()
188}
189
190func slice3(x [10]byte) []byte {
191	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
192	return v.Slice(1, 2).Bytes()
193}
194
195func elem1(x *int) int { // ERROR "x does not escape"
196	v := reflect.ValueOf(x)
197	return int(v.Elem().Int())
198}
199
200func elem2(x *string) string { // ERROR "leaking param: x to result ~r0 level=1"
201	v := reflect.ValueOf(x)
202	return string(v.Elem().String())
203}
204
205type S struct {
206	A int
207	B *int
208	C string
209}
210
211func (S) M() {}
212
213func field1(x S) int { // ERROR "x does not escape"
214	v := reflect.ValueOf(x) // ERROR "x does not escape"
215	return int(v.Field(0).Int())
216}
217
218func field2(x S) string { // ERROR "leaking param: x to result ~r0 level=0"
219	v := reflect.ValueOf(x) // ERROR "x does not escape"
220	return v.Field(2).String()
221}
222
223func numfield(x S) int { // ERROR "x does not escape"
224	v := reflect.ValueOf(x) // ERROR "x does not escape"
225	return v.NumField()
226}
227
228func index1(x []int) int { // ERROR "x does not escape"
229	v := reflect.ValueOf(x) // ERROR "x does not escape"
230	return int(v.Index(0).Int())
231}
232
233// Unfortunate: should only leak content (level=1)
234func index2(x []string) string { // ERROR "leaking param: x to result ~r0 level=0"
235	v := reflect.ValueOf(x) // ERROR "x does not escape"
236	return v.Index(0).String()
237}
238
239func index3(x [3]int) int {
240	v := reflect.ValueOf(x) // ERROR "x does not escape"
241	return int(v.Index(0).Int())
242}
243
244func index4(x [3]string) string { // ERROR "leaking param: x to result ~r0 level=0"
245	v := reflect.ValueOf(x) // ERROR "x does not escape"
246	return v.Index(0).String()
247}
248
249func index5(x string) byte { // ERROR "x does not escape"
250	v := reflect.ValueOf(x) // ERROR "x does not escape"
251	return byte(v.Index(0).Uint())
252}
253
254// Unfortunate: x (the interface storage) doesn't need to escape as the function takes a scalar arg.
255func call1(f func(int), x int) { // ERROR "leaking param: f$"
256	fv := reflect.ValueOf(f)
257	v := reflect.ValueOf(x)     // ERROR "x escapes to heap"
258	fv.Call([]reflect.Value{v}) // ERROR "\[\]reflect\.Value{\.\.\.} does not escape"
259}
260
261func call2(f func(*int), x *int) { // ERROR "leaking param: f$" "leaking param: x$"
262	fv := reflect.ValueOf(f)
263	v := reflect.ValueOf(x)
264	fv.Call([]reflect.Value{v}) // ERROR "\[\]reflect.Value{\.\.\.} does not escape"
265}
266
267func method(x S) reflect.Value { // ERROR "leaking param: x$"
268	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
269	return v.Method(0)
270}
271
272func nummethod(x S) int { // ERROR "x does not escape"
273	v := reflect.ValueOf(x) // ERROR "x does not escape"
274	return v.NumMethod()
275}
276
277// Unfortunate: k doesn't need to escape.
278func mapindex(m map[string]string, k string) string { // ERROR "m does not escape" "leaking param: k$"
279	mv := reflect.ValueOf(m)
280	kv := reflect.ValueOf(k) // ERROR "k escapes to heap"
281	return mv.MapIndex(kv).String()
282}
283
284func mapkeys(m map[string]string) []reflect.Value { // ERROR "m does not escape"
285	mv := reflect.ValueOf(m)
286	return mv.MapKeys()
287}
288
289func mapiter1(m map[string]string) *reflect.MapIter { // ERROR "leaking param: m$"
290	mv := reflect.ValueOf(m)
291	return mv.MapRange()
292}
293
294func mapiter2(m map[string]string) string { // ERROR "leaking param: m$"
295	mv := reflect.ValueOf(m)
296	it := mv.MapRange()
297	if it.Next() {
298		return it.Key().String()
299	}
300	return ""
301}
302
303func mapiter3(m map[string]string, it *reflect.MapIter) { // ERROR "leaking param: m$" "it does not escape"
304	mv := reflect.ValueOf(m)
305	it.Reset(mv)
306}
307
308func recv1(ch chan string) string { // ERROR "ch does not escape"
309	v := reflect.ValueOf(ch)
310	r, _ := v.Recv()
311	return r.String()
312}
313
314func recv2(ch chan string) string { // ERROR "ch does not escape"
315	v := reflect.ValueOf(ch)
316	r, _ := v.TryRecv()
317	return r.String()
318}
319
320// Unfortunate: x (the interface storage) doesn't need to escape.
321func send1(ch chan string, x string) { // ERROR "ch does not escape" "leaking param: x$"
322	vc := reflect.ValueOf(ch)
323	vx := reflect.ValueOf(x) // ERROR "x escapes to heap"
324	vc.Send(vx)
325}
326
327// Unfortunate: x (the interface storage) doesn't need to escape.
328func send2(ch chan string, x string) bool { // ERROR "ch does not escape" "leaking param: x$"
329	vc := reflect.ValueOf(ch)
330	vx := reflect.ValueOf(x) // ERROR "x escapes to heap"
331	return vc.TrySend(vx)
332}
333
334func close1(ch chan string) { // ERROR "ch does not escape"
335	v := reflect.ValueOf(ch)
336	v.Close()
337}
338
339func select1(ch chan string) string { // ERROR "leaking param: ch$"
340	v := reflect.ValueOf(ch)
341	cas := reflect.SelectCase{Dir: reflect.SelectRecv, Chan: v}
342	_, r, _ := reflect.Select([]reflect.SelectCase{cas}) // ERROR "\[\]reflect.SelectCase{...} does not escape"
343	return r.String()
344}
345
346// Unfortunate: x (the interface storage) doesn't need to escape.
347func select2(ch chan string, x string) { // ERROR "leaking param: ch$" "leaking param: x$"
348	vc := reflect.ValueOf(ch)
349	vx := reflect.ValueOf(x) // ERROR "x escapes to heap"
350	cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: vc, Send: vx}
351	reflect.Select([]reflect.SelectCase{cas}) // ERROR "\[\]reflect.SelectCase{...} does not escape"
352}
353
354var (
355	intTyp    = reflect.TypeOf(int(0))     // ERROR "0 does not escape"
356	uintTyp   = reflect.TypeOf(uint(0))    // ERROR "uint\(0\) does not escape"
357	stringTyp = reflect.TypeOf(string("")) // ERROR ".. does not escape"
358	bytesTyp  = reflect.TypeOf([]byte{})   // ERROR "\[\]byte{} does not escape"
359)
360
361// Unfortunate: should not escape.
362func convert1(x int) uint {
363	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
364	return uint(v.Convert(uintTyp).Uint())
365}
366
367// Unfortunate: should only escape content to result.
368func convert2(x []byte) string { // ERROR "leaking param: x$"
369	v := reflect.ValueOf(x) // ERROR "x escapes to heap"
370	return v.Convert(stringTyp).String()
371}
372
373// Unfortunate: v doesn't need to leak, x (the interface storage) doesn't need to escape.
374func set1(v reflect.Value, x int) { // ERROR "leaking param: v$"
375	vx := reflect.ValueOf(x) // ERROR "x escapes to heap"
376	v.Set(vx)
377}
378
379// Unfortunate: a can be stack allocated, x (the interface storage) doesn't need to escape.
380func set2(x int) int64 {
381	var a int // ERROR "moved to heap: a"
382	v := reflect.ValueOf(&a).Elem()
383	vx := reflect.ValueOf(x) // ERROR "x escapes to heap"
384	v.Set(vx)
385	return v.Int()
386}
387
388func set3(v reflect.Value, x int) { // ERROR "v does not escape"
389	v.SetInt(int64(x))
390}
391
392func set4(x int) int {
393	var a int
394	v := reflect.ValueOf(&a).Elem() // a should not escape, no error printed
395	v.SetInt(int64(x))
396	return int(v.Int())
397}
398
399func set5(v reflect.Value, x string) { // ERROR "v does not escape" "leaking param: x$"
400	v.SetString(x)
401}
402
403func set6(v reflect.Value, x []byte) { // ERROR "v does not escape" "leaking param: x$"
404	v.SetBytes(x)
405}
406
407func set7(v reflect.Value, x unsafe.Pointer) { // ERROR "v does not escape" "leaking param: x$"
408	v.SetPointer(x)
409}
410
411func setmapindex(m map[string]string, k, e string) { // ERROR "m does not escape" "leaking param: k$" "leaking param: e$"
412	mv := reflect.ValueOf(m)
413	kv := reflect.ValueOf(k) // ERROR "k escapes to heap"
414	ev := reflect.ValueOf(e) // ERROR "e escapes to heap"
415	mv.SetMapIndex(kv, ev)
416}
417
418// Unfortunate: k doesn't need to escape.
419func mapdelete(m map[string]string, k string) { // ERROR "m does not escape" "leaking param: k$"
420	mv := reflect.ValueOf(m)
421	kv := reflect.ValueOf(k) // ERROR "k escapes to heap"
422	mv.SetMapIndex(kv, reflect.Value{})
423}
424
425// Unfortunate: v doesn't need to leak.
426func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
427	v.SetIterKey(it)
428}
429
430// Unfortunate: v doesn't need to leak.
431func setiterkey2(v reflect.Value, m map[string]string) { // ERROR "leaking param: v$" "leaking param: m$"
432	it := reflect.ValueOf(m).MapRange()
433	v.SetIterKey(it)
434}
435
436// Unfortunate: v doesn't need to leak.
437func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
438	v.SetIterValue(it)
439}
440
441// Unfortunate: v doesn't need to leak.
442func setitervalue2(v reflect.Value, m map[string]string) { // ERROR "leaking param: v$" "leaking param: m$"
443	it := reflect.ValueOf(m).MapRange()
444	v.SetIterValue(it)
445}
446
447// Unfortunate: s doesn't need escape, only leak to result.
448// And x (interface storage) doesn't need to escape.
449func append1(s []int, x int) []int { // ERROR "leaking param: s$"
450	sv := reflect.ValueOf(s)     // ERROR "s escapes to heap"
451	xv := reflect.ValueOf(x)     // ERROR "x escapes to heap"
452	rv := reflect.Append(sv, xv) // ERROR "... argument does not escape"
453	return rv.Interface().([]int)
454}
455
456// Unfortunate: s doesn't need escape, only leak to result.
457func append2(s, x []int) []int { // ERROR "leaking param: s$" "x does not escape"
458	sv := reflect.ValueOf(s) // ERROR "s escapes to heap"
459	xv := reflect.ValueOf(x) // ERROR "x does not escape"
460	rv := reflect.AppendSlice(sv, xv)
461	return rv.Interface().([]int)
462}
463