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 12:38:21 +00:00
|
|
|
// errorcheck -0 -m -l
|
|
|
|
|
2016-04-10 21:32:26 +00: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 12:38:21 +00: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 16:00:17 +00: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 12:38:21 +00: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-14 01:59:39 +00: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 12:38:21 +00:00
|
|
|
return p, p
|
|
|
|
}
|
|
|
|
|
2014-02-14 01:59:39 +00: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 12:38:21 +00:00
|
|
|
return p, q
|
|
|
|
}
|
|
|
|
|
2014-02-14 01:59:39 +00: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 12:38:21 +00:00
|
|
|
return leaktoret22(q, p)
|
|
|
|
}
|
|
|
|
|
2014-02-14 01:59:39 +00: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 12:38:21 +00: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 20:15:21 +00: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 13:27:32 +00:00
|
|
|
// should make p leak always
|
|
|
|
global = p // ERROR "p escapes to heap"
|
2012-11-07 20:15:21 +00:00
|
|
|
return T2{p}
|
|
|
|
}
|
|
|
|
|
|
|
|
func f9() {
|
|
|
|
var j T1 // ERROR "moved to heap: j"
|
2015-05-20 19:16:34 +00:00
|
|
|
f8(&j) // ERROR "&j escapes to heap"
|
2012-11-07 20:15:21 +00:00
|
|
|
}
|
2013-08-08 17:46:30 +00:00
|
|
|
|
|
|
|
func f10() {
|
|
|
|
// These don't escape but are too big for the stack
|
2015-05-20 19:16:34 +00: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 17:46:30 +00:00
|
|
|
_ = x[0] + y[0]
|
|
|
|
}
|
2017-03-24 16:00:17 +00: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"
|
|
|
|
}
|
2018-03-07 23:10:27 +00:00
|
|
|
|
|
|
|
// Test for issue 24305 (passing to unnamed receivers does not escape).
|
|
|
|
type U int
|
|
|
|
|
|
|
|
func (*U) M() {}
|
|
|
|
func (_ *U) N() {}
|
|
|
|
|
|
|
|
func _() {
|
|
|
|
var u U
|
|
|
|
u.M() // ERROR "u does not escape"
|
|
|
|
u.N() // ERROR "u does not escape"
|
|
|
|
}
|
2018-04-06 20:21:26 +00:00
|
|
|
|
|
|
|
// Issue 24730: taking address in a loop causes unnecessary escape
|
|
|
|
type T24730 struct {
|
|
|
|
x [64]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *T24730) g() { // ERROR "t does not escape"
|
|
|
|
y := t.x[:] // ERROR "t\.x does not escape"
|
|
|
|
for i := range t.x[:] { // ERROR "t\.x does not escape"
|
|
|
|
y = t.x[:] // ERROR "t\.x does not escape"
|
|
|
|
y[i] = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
var z *byte
|
|
|
|
for i := range t.x[:] { // ERROR "t\.x does not escape"
|
|
|
|
z = &t.x[i] // ERROR "t\.x\[i\] does not escape"
|
|
|
|
*z = 2
|
|
|
|
}
|
|
|
|
}
|
2018-04-17 20:28:13 +00:00
|
|
|
|
|
|
|
// Issue 15730: copy causes unnecessary escape
|
|
|
|
|
|
|
|
var sink []byte
|
|
|
|
var sink2 []int
|
|
|
|
var sink3 []*int
|
|
|
|
|
|
|
|
func f15730a(args ...interface{}) { // ERROR "args does not escape"
|
|
|
|
for _, arg := range args {
|
|
|
|
switch a := arg.(type) {
|
|
|
|
case string:
|
|
|
|
copy(sink, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func f15730b(args ...interface{}) { // ERROR "args does not escape"
|
|
|
|
for _, arg := range args {
|
|
|
|
switch a := arg.(type) {
|
|
|
|
case []int:
|
|
|
|
copy(sink2, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func f15730c(args ...interface{}) { // ERROR "leaking param content: args"
|
|
|
|
for _, arg := range args {
|
|
|
|
switch a := arg.(type) {
|
|
|
|
case []*int:
|
|
|
|
// copy pointerful data should cause escape
|
|
|
|
copy(sink3, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|