modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/fixedbugs/issue13799.go (about) 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 12 package main 13 14 import "fmt" 15 16 func 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$" "main ... 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 34 func 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 for i := 0; i < maxI; i++ { // ERROR "moved to heap: i$" 50 // var fn func() // this makes it work, because fn stays off heap 51 j := 0 // ERROR "moved to heap: j$" 52 fn = func() { // ERROR "func literal escapes to heap$" 53 m[i] = append(m[i], 0) // ERROR "&i escapes to heap$" 54 if j < 25 { // ERROR "&j escapes to heap$" 55 j++ 56 fn() // ERROR "&fn escapes to heap$" 57 } 58 } 59 fn() 60 } 61 62 if len(m) != maxI { 63 panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "test1 ... argument does not escape$" 64 } 65 } 66 67 func test2(iter int) { 68 69 const maxI = 500 70 m := make(map[int][]int) // ERROR "test2 make\(map\[int\]\[\]int\) does not escape$" 71 72 // var fn func() 73 for i := 0; i < maxI; i++ { 74 var fn func() // this makes it work, because fn stays off heap 75 j := 0 76 fn = func() { // ERROR "test2 func literal does not escape$" 77 m[i] = append(m[i], 0) 78 if j < 25 { 79 j++ 80 fn() 81 } 82 } 83 fn() 84 } 85 86 if len(m) != maxI { 87 panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "test2 ... argument does not escape$" 88 } 89 } 90 91 func test3(iter int) { 92 93 const maxI = 500 94 var x int // ERROR "moved to heap: x$" 95 m := &x // ERROR "&x escapes to heap$" 96 97 var fn func() // ERROR "moved to heap: fn$" 98 for i := 0; i < maxI; i++ { 99 // var fn func() // this makes it work, because fn stays off heap 100 j := 0 // ERROR "moved to heap: j$" 101 fn = func() { // ERROR "func literal escapes to heap$" 102 if j < 100 { // ERROR "&j escapes to heap$" 103 j++ 104 fn() // ERROR "&fn escapes to heap$" 105 } else { 106 *m = *m + 1 107 } 108 } 109 fn() 110 } 111 112 if *m != maxI { 113 panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test3 ... argument does not escape$" 114 } 115 } 116 117 func test4(iter int) { 118 119 const maxI = 500 120 var x int 121 m := &x // ERROR "test4 &x does not escape$" 122 123 // var fn func() 124 for i := 0; i < maxI; i++ { 125 var fn func() // this makes it work, because fn stays off heap 126 j := 0 127 fn = func() { // ERROR "test4 func literal does not escape$" 128 if j < 100 { 129 j++ 130 fn() 131 } else { 132 *m = *m + 1 133 } 134 } 135 fn() 136 } 137 138 if *m != maxI { 139 panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test4 ... argument does not escape$" 140 } 141 } 142 143 type str struct { 144 m *int 145 } 146 147 func recur1(j int, s *str) { // ERROR "recur1 s does not escape" 148 if j < 100 { 149 j++ 150 recur1(j, s) 151 } else { 152 *s.m++ 153 } 154 } 155 156 func test5(iter int) { 157 158 const maxI = 500 159 var x int // ERROR "moved to heap: x$" 160 m := &x // ERROR "&x escapes to heap$" 161 162 var fn *str 163 for i := 0; i < maxI; i++ { 164 // var fn *str // this makes it work, because fn stays off heap 165 fn = &str{m} // ERROR "&str literal escapes to heap" 166 recur1(0, fn) 167 } 168 169 if *m != maxI { 170 panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test5 ... argument does not escape$" 171 } 172 } 173 174 func test6(iter int) { 175 176 const maxI = 500 177 var x int 178 m := &x // ERROR "&x does not escape$" 179 180 // var fn *str 181 for i := 0; i < maxI; i++ { 182 var fn *str // this makes it work, because fn stays off heap 183 fn = &str{m} // ERROR "&str literal does not escape" 184 recur1(0, fn) 185 } 186 187 if *m != maxI { 188 panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test6 ... argument does not escape$" 189 } 190 }