| // errorcheck -0 -m -m -l |
| |
| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Note the doubled -m; this tests the "because" explanations for escapes, |
| // and is likely to be annoyingly fragile under compiler change. |
| // As long as the explanations look reasonably sane, meaning eyeball verify output of |
| // go build -gcflags '-l -m -m' escape_because.go |
| // and investigate changes, feel free to update with |
| // go run run.go -update_errors -- escape_because.go |
| |
| package main |
| |
| func main() { |
| } |
| |
| var sink interface{} |
| |
| type pair struct { |
| x, y *int |
| } |
| |
| type Pairy interface { |
| EqualParts() bool |
| } |
| |
| func (p *pair) EqualParts() bool { // ERROR "\(\*pair\).EqualParts p does not escape$" |
| return p != nil && (p.x == p.y || *p.x == *p.y) |
| } |
| |
| func f1(p *int) { // ERROR "from \[3\]\*int literal \(array literal element\) at escape_because.go:34$" "from a \(assigned\) at escape_because.go:34$" "from a \(interface-converted\) at escape_because.go:35$" "from sink \(assigned to top level variable\) at escape_because.go:35$" "leaking param: p$" |
| a := [3]*int{p, nil, nil} |
| sink = a // ERROR "a escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:35$" |
| |
| } |
| |
| func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "from &u \(interface-converted\) at escape_because.go:43$" "from pair literal \(struct literal element\) at escape_because.go:41$" "from s \(assigned\) at escape_because.go:40$" "from sink \(assigned to top level variable\) at escape_because.go:43$" "from t \(assigned\) at escape_because.go:41$" "from u \(assigned\) at escape_because.go:42$" "leaking param: q$" |
| s := q |
| t := pair{s, nil} |
| u := t // ERROR "moved to heap: u$" |
| sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:43$" |
| } |
| |
| func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r to result ~r1 level=-1$" |
| c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" |
| return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:48$" |
| } |
| |
| func f4(a *int, s []*int) int { // ERROR "from \*s \(indirection\) at escape_because.go:51$" "from append\(s, a\) \(appended to slice\) at escape_because.go:52$" "from append\(s, a\) \(appendee slice\) at escape_because.go:52$" "leaking param content: s$" "leaking param: a$" |
| s = append(s, a) |
| return *(s[0]) |
| } |
| |
| func f5(s1, s2 []*int) int { // ERROR "from \*s1 \(indirection\) at escape_because.go:56$" "from \*s2 \(indirection\) at escape_because.go:56$" "from append\(s1, s2...\) \(appended slice...\) at escape_because.go:57$" "from append\(s1, s2...\) \(appendee slice\) at escape_because.go:57$" "leaking param content: s1$" "leaking param content: s2$" |
| s1 = append(s1, s2...) |
| return *(s1[0]) |
| } |
| |
| func f6(x, y *int) bool { // ERROR "f6 x does not escape$" "f6 y does not escape$" |
| p := pair{x, y} |
| var P Pairy = &p // ERROR "f6 &p does not escape$" |
| pp := P.(*pair) |
| return pp.EqualParts() |
| } |
| |
| func f7(x map[int]*int, y int) *int { // ERROR "f7 x does not escape$" |
| z, ok := x[y] |
| if !ok { |
| return nil |
| } |
| return z |
| } |
| |
| func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go:78$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" "leaking param: y$" "moved to heap: x$" |
| if x <= 0 { |
| return y |
| } |
| x-- |
| return f8(*y, &x) // ERROR "&x escapes to heap$" "from y \(arg to recursive call\) at escape_because.go:81$" "from ~r2 \(return\) at escape_because.go:78$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" |
| } |
| |
| func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at escape_because.go:86$" "from ~r2 \(return\) at escape_because.go:86$" "from ~r2 \(returned from recursive function\) at escape_because.go:84$" "leaking param content: y$" "leaking param: y to result ~r2 level=1$" "moved to heap: x$" |
| if x <= 0 { |
| return y[0] |
| } |
| x-- |
| return f9(*y[0], &x) // ERROR "&x escapes to heap$" "f9 ... argument does not escape$" "from ... argument \(... arg to recursive call\) at escape_because.go:89$" |
| } |
| |
| func f10(x map[*int]*int, y, z *int) *int { // ERROR "f10 x does not escape$" "from x\[y\] \(key of map put\) at escape_because.go:93$" "from x\[y\] \(value of map put\) at escape_because.go:93$" "leaking param: y$" "leaking param: z$" |
| x[y] = z |
| return z |
| } |
| |
| func f11(x map[*int]*int, y, z *int) map[*int]*int { // ERROR "f11 x does not escape$" "from map\[\*int\]\*int literal \(map literal key\) at escape_because.go:98$" "from map\[\*int\]\*int literal \(map literal value\) at escape_because.go:98$" "leaking param: y$" "leaking param: z$" |
| return map[*int]*int{y: z} // ERROR "from ~r3 \(return\) at escape_because.go:98$" "map\[\*int\]\*int literal escapes to heap$" |
| } |
| |
| func f12() { |
| b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from b \(assigned\) at escape_because.go:102$" "from b \(passed to call\[argument escapes\]\) at escape_because.go:103$" |
| escape(b) |
| } |
| |
| func escape(b []byte) { // ERROR "from panic\(b\) \(panic\) at escape_because.go:107$" "leaking param: b$" |
| panic(b) |
| } |
| |
| func f13() { |
| b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from .out0 \(passed-to-and-returned-from-call\) at escape_because.go:112$" "from b \(assigned\) at escape_because.go:111$" "from c \(assigned\) at escape_because.go:112$" "from c \(passed to call\[argument escapes\]\) at escape_because.go:113$" |
| c := transmit(b) |
| escape(c) |
| } |
| |
| //go:noinline |
| func transmit(b []byte) []byte { // ERROR "from ~r1 \(return\) at escape_because.go:118$" "leaking param: b to result ~r1 level=0$" |
| return b |
| } |
| |
| func f14() { |
| n := 32 |
| s1 := make([]int, n) // ERROR "make\(\[\]int, n\) escapes to heap" "from make\(\[\]int, n\) \(non-constant size\)" |
| s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, n\) escapes to heap" "from make\(\[\]int, 0, n\) \(non-constant size\)" |
| _, _ = s1, s2 |
| } |
| |
| // The list below is all of the why-escapes messages seen building the escape analysis tests. |
| /* |
| for i in escape*go ; do echo compile $i; go build -gcflags '-l -m -m' $i >& `basename $i .go`.log ; done |
| grep 'from .* at ' escape*.log | sed -e 's/^.*(\([^()]*\))[^()]*$/\1/' | sort -u |
| */ |
| // sed RE above assumes that (reason) is the last parenthesized phrase in the line, |
| // and that none of the reasons contains any parentheses |
| |
| /* |
| ... arg to recursive call |
| address-of |
| appended slice... |
| appended to slice |
| appendee slice |
| arg to ... |
| arg to recursive call |
| array-element-equals |
| array literal element |
| assigned |
| assigned to top level variable |
| assign-pair-dot-type |
| assign-pair-func-call |
| captured by a closure |
| captured by called closure |
| dot |
| dot-equals |
| dot of pointer |
| fixed-array-index-of |
| go func arg |
| indirection |
| interface-converted |
| key of map put |
| map literal key |
| map literal value |
| non-constant size |
| panic |
| parameter to indirect call |
| passed-to-and-returned-from-call |
| passed to call[argument content escapes] |
| passed to call[argument escapes] |
| pointer literal |
| range-deref |
| receiver in indirect call |
| return |
| returned from recursive function |
| slice-element-equals |
| slice-literal-element |
| star-dot-equals |
| star-equals |
| struct literal element |
| too large for stack |
| value of map put |
| */ |
| |
| // Expected, but not yet seen (they may be unreachable): |
| |
| /* |
| append-first-arg |
| assign-pair-mapr |
| assign-pair-receive |
| call receiver |
| map index |
| pointer literal [assign] |
| slice literal element |
| */ |