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, using compiler diagnostic flags, that the escape analysis is working.
8// Compiles but does not run.  Inlining is disabled.
9// Registerization is disabled too (-N), which should
10// have no effect on escape analysis.
11
12package main
13
14import "fmt"
15
16func main() {
17	// Just run test over and over again. This main func is just for
18	// convenience; if test were the main func, we could also trigger
19	// the panic just by running the program over and over again
20	// (sometimes it takes 1 time, sometimes it takes ~4,000+).
21	for iter := 0; ; iter++ {
22		if iter%50 == 0 {
23			fmt.Println(iter) // ERROR "iter escapes to heap$" "... argument does not escape$"
24		}
25		test1(iter)
26		test2(iter)
27		test3(iter)
28		test4(iter)
29		test5(iter)
30		test6(iter)
31	}
32}
33
34func test1(iter int) {
35
36	const maxI = 500
37	m := make(map[int][]int) // ERROR "make\(map\[int\]\[\]int\) escapes to heap$"
38
39	// The panic seems to be triggered when m is modified inside a
40	// closure that is both recursively called and reassigned to in a
41	// loop.
42
43	// Cause of bug -- escape of closure failed to escape (shared) data structures
44	// of map.  Assign to fn declared outside of loop triggers escape of closure.
45	// Heap -> stack pointer eventually causes badness when stack reallocation
46	// occurs.
47
48	var fn func() // ERROR "moved to heap: fn$"
49	i := 0        // ERROR "moved to heap: i$"
50	for ; i < maxI; i++ {
51		// var fn func() // this makes it work, because fn stays off heap
52		j := 0        // ERROR "moved to heap: j$"
53		fn = func() { // ERROR "func literal escapes to heap$"
54			m[i] = append(m[i], 0)
55			if j < 25 {
56				j++
57				fn()
58			}
59		}
60		fn()
61	}
62
63	if len(m) != maxI {
64		panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
65	}
66}
67
68func test2(iter int) {
69
70	const maxI = 500
71	m := make(map[int][]int) // ERROR "make\(map\[int\]\[\]int\) does not escape$"
72
73	// var fn func()
74	for i := 0; i < maxI; i++ {
75		var fn func() // this makes it work, because fn stays off heap
76		j := 0
77		fn = func() { // ERROR "func literal does not escape$"
78			m[i] = append(m[i], 0)
79			if j < 25 {
80				j++
81				fn()
82			}
83		}
84		fn()
85	}
86
87	if len(m) != maxI {
88		panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
89	}
90}
91
92func test3(iter int) {
93
94	const maxI = 500
95	var x int // ERROR "moved to heap: x$"
96	m := &x
97
98	var fn func() // ERROR "moved to heap: fn$"
99	for i := 0; i < maxI; i++ {
100		// var fn func() // this makes it work, because fn stays off heap
101		j := 0        // ERROR "moved to heap: j$"
102		fn = func() { // ERROR "func literal escapes to heap$"
103			if j < 100 {
104				j++
105				fn()
106			} else {
107				*m = *m + 1
108			}
109		}
110		fn()
111	}
112
113	if *m != maxI {
114		panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
115	}
116}
117
118func test4(iter int) {
119
120	const maxI = 500
121	var x int
122	m := &x
123
124	// var fn func()
125	for i := 0; i < maxI; i++ {
126		var fn func() // this makes it work, because fn stays off heap
127		j := 0
128		fn = func() { // ERROR "func literal does not escape$"
129			if j < 100 {
130				j++
131				fn()
132			} else {
133				*m = *m + 1
134			}
135		}
136		fn()
137	}
138
139	if *m != maxI {
140		panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
141	}
142}
143
144type str struct {
145	m *int
146}
147
148func recur1(j int, s *str) { // ERROR "s does not escape"
149	if j < 100 {
150		j++
151		recur1(j, s)
152	} else {
153		*s.m++
154	}
155}
156
157func test5(iter int) {
158
159	const maxI = 500
160	var x int // ERROR "moved to heap: x$"
161	m := &x
162
163	var fn *str
164	for i := 0; i < maxI; i++ {
165		// var fn *str // this makes it work, because fn stays off heap
166		fn = &str{m} // ERROR "&str{...} escapes to heap"
167		recur1(0, fn)
168	}
169
170	if *m != maxI {
171		panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
172	}
173}
174
175func test6(iter int) {
176
177	const maxI = 500
178	var x int
179	m := &x
180
181	// var fn *str
182	for i := 0; i < maxI; i++ {
183		var fn *str  // this makes it work, because fn stays off heap
184		fn = &str{m} // ERROR "&str{...} does not escape"
185		recur1(0, fn)
186	}
187
188	if *m != maxI {
189		panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "500 escapes to heap$" "... argument does not escape$" "fmt.Sprintf\(.*\) escapes to heap"
190	}
191}
192