Home | History | Annotate | Download | only in fixedbugs
      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 }
    191