mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 08:40:55 +00:00 
			
		
		
		
	 bea5252a13
			
		
	
	
		bea5252a13
		
	
	
	
	
		
			
			Sometimes neither the src nor the dst of an escape edge contains the line number appropriate to the edge, so add a field so that can be set correctly. Also updated some of the explanations to be less jargon-y and perhaps more informative, and folded bug example into test. Cleaned up some of the function/method names in esc.go and did a quick sanity check that each "bundling" function was actually called often enough to justify its existence. Fixes #17459. Change-Id: Ieba53ab0a6ba1f7a6c4962bc0b702ede9cc3a3cc Reviewed-on: https://go-review.googlesource.com/31660 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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
 | |
| }
 | |
| 
 | |
| // 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 literal element
 | |
| array-element-equals
 | |
| assign-pair
 | |
| assign-pair-dot-type
 | |
| assign-pair-func-call
 | |
| assigned
 | |
| assigned to top level variable
 | |
| call part
 | |
| captured by a closure
 | |
| closure-var
 | |
| converted
 | |
| copied slice
 | |
| defer func
 | |
| defer func ...
 | |
| defer func arg
 | |
| dot
 | |
| dot of pointer
 | |
| dot-equals
 | |
| fixed-array-index-of
 | |
| go func
 | |
| go func ...
 | |
| go func arg
 | |
| indirection
 | |
| interface-converted
 | |
| key of map put
 | |
| map literal key
 | |
| map literal value
 | |
| parameter to indirect call
 | |
| passed to call[argument content escapes]
 | |
| passed to call[argument escapes]
 | |
| passed-to-and-returned-from-call
 | |
| pointer literal
 | |
| range
 | |
| range-deref
 | |
| receiver in indirect call
 | |
| return
 | |
| returned from recursive function
 | |
| send
 | |
| slice
 | |
| slice-element-equals
 | |
| slice-literal-element
 | |
| star-dot-equals
 | |
| star-equals
 | |
| struct literal element
 | |
| switch case
 | |
| 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
 | |
| panic
 | |
| pointer literal [assign]
 | |
| slice literal element
 | |
| */
 |