| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | // errorcheck -0 -m -l | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-10 14:32:26 -07:00
										 |  |  | // Copyright 2012 The Go Authors. All rights reserved. | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Test, using compiler diagnostic flags, that the escape analysis is working. | 
					
						
							|  |  |  | // Compiles but does not run.  Inlining is disabled. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package foo | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 09:00:17 -07:00
										 |  |  | import "runtime" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | func noleak(p *int) int { // ERROR "p does not escape" | 
					
						
							|  |  |  | 	return *p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leaktoret(p *int) *int { // ERROR "leaking param: p to result" | 
					
						
							|  |  |  | 	return p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 20:59:39 -05:00
										 |  |  | func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2" | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | 	return p, p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 20:59:39 -05:00
										 |  |  | func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3" | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | 	return p, q | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 20:59:39 -05:00
										 |  |  | func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | 	return leaktoret22(q, p) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 20:59:39 -05:00
										 |  |  | func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" | 
					
						
							| 
									
										
										
											
												cmd/gc: escape analysis to track flow of in to out parameters.
includes step 0: synthesize outparams, from 6600044
includes step 1,2: give outparams loopdepth 0 and verify unchanged results
         generate esc:$mask tags, but still tie to sink if a param has mask != 0
from 6610054
adds final steps:
- have esccall generate n->escretval, a list of nodes the function results flow to
- use these in esccall and ORETURN/OAS2FUNC/and f(g())
- only tie parameters to sink if tag is absent, otherwise according to mask, tie them to escretval
R=rsc, bradfitz
CC=dave, gobot, golang-dev, iant, rsc
https://golang.org/cl/6741044
											
										 
											2012-10-29 13:38:21 +01:00
										 |  |  | 	r, s := leaktoret22(q, p) | 
					
						
							|  |  |  | 	return r, s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" | 
					
						
							|  |  |  | 	r, s = leaktoret22(q, p) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" | 
					
						
							|  |  |  | 	r, s = leaktoret22(q, p) | 
					
						
							|  |  |  | 	return r, s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" | 
					
						
							|  |  |  | 	rr, ss := leaktoret22(q, p) | 
					
						
							|  |  |  | 	return rr, ss | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var gp *int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leaktosink(p *int) *int { // ERROR "leaking param: p" | 
					
						
							|  |  |  | 	gp = p | 
					
						
							|  |  |  | 	return p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f1() { | 
					
						
							|  |  |  | 	var x int | 
					
						
							|  |  |  | 	p := noleak(&x) // ERROR "&x does not escape" | 
					
						
							|  |  |  | 	_ = p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f2() { | 
					
						
							|  |  |  | 	var x int | 
					
						
							|  |  |  | 	p := leaktoret(&x) // ERROR "&x does not escape" | 
					
						
							|  |  |  | 	_ = p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f3() { | 
					
						
							|  |  |  | 	var x int          // ERROR "moved to heap: x" | 
					
						
							|  |  |  | 	p := leaktoret(&x) // ERROR "&x escapes to heap" | 
					
						
							|  |  |  | 	gp = p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f4() { | 
					
						
							|  |  |  | 	var x int              // ERROR "moved to heap: x" | 
					
						
							|  |  |  | 	p, q := leaktoret2(&x) // ERROR "&x escapes to heap" | 
					
						
							|  |  |  | 	gp = p | 
					
						
							|  |  |  | 	gp = q | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f5() { | 
					
						
							|  |  |  | 	var x int | 
					
						
							|  |  |  | 	leaktoret22(leaktoret2(&x)) // ERROR "&x does not escape" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f6() { | 
					
						
							|  |  |  | 	var x int                               // ERROR "moved to heap: x" | 
					
						
							|  |  |  | 	px1, px2 := leaktoret22(leaktoret2(&x)) // ERROR "&x escapes to heap" | 
					
						
							|  |  |  | 	gp = px1 | 
					
						
							|  |  |  | 	_ = px2 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type T struct{ x int } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result" | 
					
						
							|  |  |  | 	t.x += u | 
					
						
							|  |  |  | 	return t, true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f7() *T { | 
					
						
							|  |  |  | 	r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap" | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" | 
					
						
							|  |  |  | 	return leakrecursive2(q, p) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" | 
					
						
							|  |  |  | 	if *p > *q { | 
					
						
							|  |  |  | 		return leakrecursive1(q, p) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges. | 
					
						
							|  |  |  | 	return p, q | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-07 15:15:21 -05:00
										 |  |  | var global interface{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type T1 struct { | 
					
						
							|  |  |  | 	X *int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type T2 struct { | 
					
						
							|  |  |  | 	Y *T1 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p" | 
					
						
							|  |  |  | 	if p == nil { | 
					
						
							|  |  |  | 		k = T2{} | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 16:27:32 +03:00
										 |  |  | 	// should make p leak always | 
					
						
							|  |  |  | 	global = p // ERROR "p escapes to heap" | 
					
						
							| 
									
										
										
										
											2012-11-07 15:15:21 -05:00
										 |  |  | 	return T2{p} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func f9() { | 
					
						
							|  |  |  | 	var j T1 // ERROR "moved to heap: j" | 
					
						
							| 
									
										
										
										
											2015-05-20 15:16:34 -04:00
										 |  |  | 	f8(&j)   // ERROR "&j escapes to heap" | 
					
						
							| 
									
										
										
										
											2012-11-07 15:15:21 -05:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-08 13:46:30 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | func f10() { | 
					
						
							|  |  |  | 	// These don't escape but are too big for the stack | 
					
						
							| 
									
										
										
										
											2015-05-20 15:16:34 -04:00
										 |  |  | 	var x [1 << 30]byte         // ERROR "moved to heap: x" | 
					
						
							|  |  |  | 	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap" | 
					
						
							| 
									
										
										
										
											2013-08-08 13:46:30 -04:00
										 |  |  | 	_ = x[0] + y[0] | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-24 09:00:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Test for issue 19687 (passing to unnamed parameters does not escape). | 
					
						
							|  |  |  | func f11(**int) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func f12(_ **int) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func f13() { | 
					
						
							|  |  |  | 	var x *int | 
					
						
							|  |  |  | 	f11(&x)               // ERROR "&x does not escape" | 
					
						
							|  |  |  | 	f12(&x)               // ERROR "&x does not escape" | 
					
						
							|  |  |  | 	runtime.KeepAlive(&x) // ERROR "&x does not escape" | 
					
						
							|  |  |  | } |