test: add tests for escape analysis of interface conversions
The false positives (var incorrectly escapes) are marked with BAD.
Change-Id: If64fabb6ea96de44a1177d9ab12e2ccc579fe0c4
Reviewed-on: https://go-review.googlesource.com/5294
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/test/escape2.go b/test/escape2.go
index 69c5913..591e6e1 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -475,12 +475,13 @@
func foo67() {
var mv MV
- foo63(mv)
+ foo63(mv) // ERROR "mv does not escape"
}
func foo68() {
var mv MV
- foo64(mv) // escapes but it's an int so irrelevant
+ // escapes but it's an int so irrelevant
+ foo64(mv) // ERROR "mv escapes to heap"
}
func foo69(m M) { // ERROR "leaking param: m"
@@ -488,7 +489,7 @@
}
func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
- m = mv1
+ m = mv1 // ERROR "mv1 escapes to heap"
foo64(m)
}
@@ -619,62 +620,62 @@
}
func foo75(z *int) { // ERROR "z does not escape"
- myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75a(z *int) { // ERROR "z does not escape"
- myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75esc(z *int) { // ERROR "leaking param: z"
- gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75aesc(z *int) { // ERROR "z does not escape"
var ppi **interface{} // assignments to pointer dereferences lose track
- *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75aesc1(z *int) { // ERROR "z does not escape"
- sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
// BAD: z does not escape here
func foo76(z *int) { // ERROR "leaking param: z"
- myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+ myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
}
// BAD: z does not escape here
func foo76a(z *int) { // ERROR "leaking param: z"
- myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+ myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
}
func foo76b() {
- myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76c() {
- myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76d() {
- defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76e() {
- defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76f() {
for {
// TODO: This one really only escapes its scope, but we don't distinguish yet.
- defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
}
func foo76g() {
for {
- defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
}
@@ -692,7 +693,7 @@
}
func foo77c(z []interface{}) { // ERROR "leaking param: z"
- sink = myprint1(nil, z...)
+ sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
}
func dotdotdot() {
@@ -1151,16 +1152,16 @@
func foo121() {
for i := 0; i < 10; i++ {
- defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
- go myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+ go myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
}
}
// same as foo121 but check across import
func foo121b() {
for i := 0; i < 10; i++ {
- defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
- go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
+ defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+ go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
}
}
@@ -1347,7 +1348,7 @@
T *T
}
t := &T{} // ERROR "&T literal escapes to heap"
- return U{
+ return U{ // ERROR "U literal escapes to heap"
X: t.X,
T: t,
}
@@ -1582,14 +1583,14 @@
// Literal does not escape, but element does.
i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
- sink = *x
+ sink = *x // ERROR "\*x escapes to heap"
}
func ptrlitEscape() {
// Both literal and element escape.
i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
// self-assignments
@@ -1621,7 +1622,7 @@
func (b *Buffer) bat() { // ERROR "leaking param: b"
o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
o.buf1 = b.buf1[1:2]
- sink = o
+ sink = o // ERROR "o escapes to heap"
}
func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
@@ -1639,9 +1640,9 @@
// to just x, and thus &i looks escaping.
func fieldFlowTracking() {
var x StructWithString
- i := 0 // ERROR "moved to heap: i"
- x.p = &i // ERROR "&i escapes to heap"
- sink = x.s
+ i := 0 // ERROR "moved to heap: i"
+ x.p = &i // ERROR "&i escapes to heap"
+ sink = x.s // ERROR "x.s escapes to heap"
}
// String operations.
@@ -1670,7 +1671,7 @@
b := make([]byte, 20) // ERROR "does not escape"
s := string(b) // ERROR "string\(b\) escapes to heap"
s1 := s[0:1]
- sink = s1
+ sink = s1 // ERROR "s1 escapes to heap"
}
func addstr0() {
@@ -1700,7 +1701,7 @@
s1 := "b"
s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
s2 := s[0:1]
- sink = s2
+ sink = s2 // ERROR "s2 escapes to heap"
}
func intstring0() bool {
@@ -1777,7 +1778,7 @@
m[0] = 0
m[1]++
delete(m, 1)
- sink = m[0]
+ sink = m[0] // ERROR "m\[0\] escapes to heap"
}
func makemap1() map[int]int {
@@ -1786,5 +1787,13 @@
func makemap2() {
m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
- sink = m
+ sink = m // ERROR "m escapes to heap"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
+ return m["foo"] // ERROR `"foo" does not escape`
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
+ return m[MV(0)] // ERROR "MV\(0\) does not escape"
}
diff --git a/test/escape2n.go b/test/escape2n.go
index 5e58537..59f64c0 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -475,12 +475,13 @@
func foo67() {
var mv MV
- foo63(mv)
+ foo63(mv) // ERROR "mv does not escape"
}
func foo68() {
var mv MV
- foo64(mv) // escapes but it's an int so irrelevant
+ // escapes but it's an int so irrelevant
+ foo64(mv) // ERROR "mv escapes to heap"
}
func foo69(m M) { // ERROR "leaking param: m"
@@ -488,7 +489,7 @@
}
func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
- m = mv1
+ m = mv1 // ERROR "mv1 escapes to heap"
foo64(m)
}
@@ -619,62 +620,62 @@
}
func foo75(z *int) { // ERROR "z does not escape"
- myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75a(z *int) { // ERROR "z does not escape"
- myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75esc(z *int) { // ERROR "leaking param: z"
- gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75aesc(z *int) { // ERROR "z does not escape"
var ppi **interface{} // assignments to pointer dereferences lose track
- *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo75aesc1(z *int) { // ERROR "z does not escape"
- sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
// BAD: z does not escape here
func foo76(z *int) { // ERROR "leaking param: z"
- myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+ myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
}
// BAD: z does not escape here
func foo76a(z *int) { // ERROR "leaking param: z"
- myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+ myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
}
func foo76b() {
- myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76c() {
- myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76d() {
- defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76e() {
- defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+ defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
func foo76f() {
for {
// TODO: This one really only escapes its scope, but we don't distinguish yet.
- defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
}
func foo76g() {
for {
- defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
}
}
@@ -692,7 +693,7 @@
}
func foo77c(z []interface{}) { // ERROR "leaking param: z"
- sink = myprint1(nil, z...)
+ sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
}
func dotdotdot() {
@@ -1151,16 +1152,16 @@
func foo121() {
for i := 0; i < 10; i++ {
- defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
- go myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
+ defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+ go myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
}
}
// same as foo121 but check across import
func foo121b() {
for i := 0; i < 10; i++ {
- defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
- go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
+ defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+ go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
}
}
@@ -1347,7 +1348,7 @@
T *T
}
t := &T{} // ERROR "&T literal escapes to heap"
- return U{
+ return U{ // ERROR "U literal escapes to heap"
X: t.X,
T: t,
}
@@ -1582,14 +1583,14 @@
// Literal does not escape, but element does.
i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
- sink = *x
+ sink = *x // ERROR "\*x escapes to heap"
}
func ptrlitEscape() {
// Both literal and element escape.
i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
// self-assignments
@@ -1621,7 +1622,7 @@
func (b *Buffer) bat() { // ERROR "leaking param: b"
o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
o.buf1 = b.buf1[1:2]
- sink = o
+ sink = o // ERROR "o escapes to heap"
}
func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
@@ -1639,9 +1640,9 @@
// to just x, and thus &i looks escaping.
func fieldFlowTracking() {
var x StructWithString
- i := 0 // ERROR "moved to heap: i"
- x.p = &i // ERROR "&i escapes to heap"
- sink = x.s
+ i := 0 // ERROR "moved to heap: i"
+ x.p = &i // ERROR "&i escapes to heap"
+ sink = x.s // ERROR "x.s escapes to heap"
}
// String operations.
@@ -1670,7 +1671,7 @@
b := make([]byte, 20) // ERROR "does not escape"
s := string(b) // ERROR "string\(b\) escapes to heap"
s1 := s[0:1]
- sink = s1
+ sink = s1 // ERROR "s1 escapes to heap"
}
func addstr0() {
@@ -1700,7 +1701,7 @@
s1 := "b"
s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
s2 := s[0:1]
- sink = s2
+ sink = s2 // ERROR "s2 escapes to heap"
}
func intstring0() bool {
@@ -1777,7 +1778,7 @@
m[0] = 0
m[1]++
delete(m, 1)
- sink = m[0]
+ sink = m[0] // ERROR "m\[0\] escapes to heap"
}
func makemap1() map[int]int {
@@ -1786,5 +1787,13 @@
func makemap2() {
m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
- sink = m
+ sink = m // ERROR "m escapes to heap"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
+ return m["foo"] // ERROR `"foo" does not escape`
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
+ return m[MV(0)] // ERROR "MV\(0\) does not escape"
}
diff --git a/test/escape5.go b/test/escape5.go
index a33daee..1d411b3 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -134,7 +134,8 @@
return
}
- global = p // should make p leak always
+ // should make p leak always
+ global = p // ERROR "p escapes to heap"
return T2{p}
}
diff --git a/test/escape_closure.go b/test/escape_closure.go
index 73578e4..0a5f326 100644
--- a/test/escape_closure.go
+++ b/test/escape_closure.go
@@ -41,7 +41,7 @@
func ClosureCallArgs3() {
x := 0 // ERROR "moved to heap: x"
func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
- sink = p
+ sink = p // ERROR "p escapes to heap"
}(&x) // ERROR "&x escapes to heap"
}
@@ -57,7 +57,7 @@
x := 0 // ERROR "moved to heap: x"
sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape"
return p
- }(&x) // ERROR "&x escapes to heap"
+ }(&x) // ERROR "&x escapes to heap" "\(func literal\)\(&x\) escapes to heap"
}
func ClosureCallArgs6() {
@@ -108,7 +108,7 @@
func ClosureCallArgs11() {
x := 0 // ERROR "moved to heap: x"
defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
- sink = p
+ sink = p // ERROR "p escapes to heap"
}(&x) // ERROR "&x escapes to heap"
}
@@ -143,5 +143,5 @@
sink = func(p **int) *int { // ERROR "leaking param p content to result ~r1" "func literal does not escape"
return *p
// BAD: p should not escape here
- }(&p) // ERROR "&p escapes to heap"
+ }(&p) // ERROR "&p escapes to heap" "\(func literal\)\(&p\) escapes to heap"
}
diff --git a/test/escape_field.go b/test/escape_field.go
index 0ad1144..dcf8a31 100644
--- a/test/escape_field.go
+++ b/test/escape_field.go
@@ -24,7 +24,7 @@
i := 0 // ERROR "moved to heap: i$"
var x X
x.p1 = &i // ERROR "&i escapes to heap$"
- sink = x.p1
+ sink = x.p1 // ERROR "x\.p1 escapes to heap"
}
func field1() {
@@ -32,14 +32,14 @@
var x X
// BAD: &i should not escape
x.p1 = &i // ERROR "&i escapes to heap$"
- sink = x.p2
+ sink = x.p2 // ERROR "x\.p2 escapes to heap"
}
func field3() {
i := 0 // ERROR "moved to heap: i$"
var x X
x.p1 = &i // ERROR "&i escapes to heap$"
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
func field4() {
@@ -47,7 +47,7 @@
var y Y
y.x.p1 = &i // ERROR "&i escapes to heap$"
x := y.x
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
func field5() {
@@ -55,12 +55,12 @@
var x X
// BAD: &i should not escape here
x.a[0] = &i // ERROR "&i escapes to heap$"
- sink = x.a[1]
+ sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap"
}
// BAD: we are not leaking param x, only x.p2
func field6(x *X) { // ERROR "leaking param: x$"
- sink = x.p2
+ sink = x.p2 // ERROR "x\.p2 escapes to heap"
}
func field6a() {
@@ -89,7 +89,7 @@
x := y.x
var y1 Y
y1.x = x
- sink = y1.x.p1
+ sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap"
}
func field9() {
@@ -99,7 +99,7 @@
x := y.x
var y1 Y
y1.x = x
- sink = y1.x
+ sink = y1.x // ERROR "y1\.x escapes to heap"
}
func field10() {
@@ -110,39 +110,39 @@
x := y.x
var y1 Y
y1.x = x
- sink = y1.x.p2
+ sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap"
}
func field11() {
i := 0 // ERROR "moved to heap: i$"
x := X{p1: &i} // ERROR "&i escapes to heap$"
- sink = x.p1
+ sink = x.p1 // ERROR "x\.p1 escapes to heap"
}
func field12() {
i := 0 // ERROR "moved to heap: i$"
// BAD: &i should not escape
x := X{p1: &i} // ERROR "&i escapes to heap$"
- sink = x.p2
+ sink = x.p2 // ERROR "x\.p2 escapes to heap"
}
func field13() {
i := 0 // ERROR "moved to heap: i$"
x := &X{p1: &i} // ERROR "&i escapes to heap$" "field13 &X literal does not escape$"
- sink = x.p1
+ sink = x.p1 // ERROR "x\.p1 escapes to heap"
}
func field14() {
i := 0 // ERROR "moved to heap: i$"
// BAD: &i should not escape
x := &X{p1: &i} // ERROR "&i escapes to heap$" "field14 &X literal does not escape$"
- sink = x.p2
+ sink = x.p2 // ERROR "x\.p2 escapes to heap"
}
func field15() {
i := 0 // ERROR "moved to heap: i$"
x := &X{p1: &i} // ERROR "&X literal escapes to heap$" "&i escapes to heap$"
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
func field16() {
@@ -150,18 +150,18 @@
var x X
// BAD: &i should not escape
x.p1 = &i // ERROR "&i escapes to heap$"
- var iface interface{} = x
+ var iface interface{} = x // ERROR "x escapes to heap"
x1 := iface.(X)
- sink = x1.p2
+ sink = x1.p2 // ERROR "x1\.p2 escapes to heap"
}
func field17() {
i := 0 // ERROR "moved to heap: i$"
var x X
x.p1 = &i // ERROR "&i escapes to heap$"
- var iface interface{} = x
+ var iface interface{} = x // ERROR "x escapes to heap"
x1 := iface.(X)
- sink = x1.p1
+ sink = x1.p1 // ERROR "x1\.p1 escapes to heap"
}
func field18() {
@@ -169,7 +169,7 @@
var x X
// BAD: &i should not escape
x.p1 = &i // ERROR "&i escapes to heap$"
- var iface interface{} = x
+ var iface interface{} = x // ERROR "x escapes to heap"
y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized.
- sink = y
+ sink = y // ERROR "y escapes to heap"
}
diff --git a/test/escape_iface.go b/test/escape_iface.go
new file mode 100644
index 0000000..3bc914c
--- /dev/null
+++ b/test/escape_iface.go
@@ -0,0 +1,211 @@
+// errorcheck -0 -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.
+
+// Test escape analysis for interface conversions.
+
+package escape
+
+var sink interface{}
+
+type M interface {
+ M()
+}
+
+func mescapes(m M) { // ERROR "leaking param: m"
+ sink = m // ERROR "m escapes to heap"
+}
+
+func mdoesnotescape(m M) { // ERROR "m does not escape"
+}
+
+// Tests for type stored directly in iface and with value receiver method.
+type M0 struct {
+ p *int
+}
+
+func (M0) M() {
+}
+
+func efaceEscape0() {
+ {
+ i := 0
+ v := M0{&i} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ _ = x
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M0{&i} // ERROR "&i escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ sink = x // ERROR "x escapes to heap"
+ }
+ {
+ i := 0
+ v := M0{&i} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ v1 := x.(M0)
+ _ = v1
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M0{&i} // ERROR "&i escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ v1 := x.(M0)
+ sink = v1 // ERROR "v1 escapes to heap"
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M0{&i} // ERROR "&i escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ x.M()
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M0{&i} // ERROR "&i escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ mescapes(x)
+ }
+ {
+ i := 0
+ v := M0{&i} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ mdoesnotescape(x)
+ }
+}
+
+// Tests for type stored indirectly in iface and with value receiver method.
+type M1 struct {
+ p *int
+ x int
+}
+
+func (M1) M() {
+}
+
+func efaceEscape1() {
+ {
+ i := 0
+ v := M1{&i, 0} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ _ = x
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M1{&i, 0} // ERROR "&i escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ sink = x // ERROR "x escapes to heap"
+ }
+ {
+ i := 0
+ v := M1{&i, 0} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ v1 := x.(M1)
+ _ = v1
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M1{&i, 0} // ERROR "&i escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ v1 := x.(M1)
+ sink = v1 // ERROR "v1 escapes to heap"
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M1{&i, 0} // ERROR "&i escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ x.M()
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := M1{&i, 0} // ERROR "&i escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ mescapes(x)
+ }
+ {
+ i := 0
+ v := M1{&i, 0} // ERROR "&i does not escape"
+ var x M = v // ERROR "v does not escape"
+ mdoesnotescape(x)
+ }
+}
+
+// Tests for type stored directly in iface and with pointer receiver method.
+type M2 struct {
+ p *int
+}
+
+func (*M2) M() {
+}
+
+func efaceEscape2() {
+ {
+ i := 0
+ v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+ var x M = v // ERROR "v does not escape"
+ _ = x
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ sink = x // ERROR "x escapes to heap"
+ }
+ {
+ i := 0
+ v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+ var x M = v // ERROR "v does not escape"
+ v1 := x.(*M2)
+ _ = v1
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ v1 := x.(*M2)
+ sink = v1 // ERROR "v1 escapes to heap"
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v does not escape"
+ v1 := x.(*M2)
+ sink = *v1 // ERROR "v1 escapes to heap"
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v does not escape"
+ v1, ok := x.(*M2)
+ sink = *v1 // ERROR "v1 escapes to heap"
+ _ = ok
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+ // BAD: v does not escape to heap here
+ var x M = v // ERROR "v escapes to heap"
+ x.M()
+ }
+ {
+ i := 0 // ERROR "moved to heap: i"
+ v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+ var x M = v // ERROR "v escapes to heap"
+ mescapes(x)
+ }
+ {
+ i := 0
+ v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+ var x M = v // ERROR "v does not escape"
+ mdoesnotescape(x)
+ }
+}
diff --git a/test/escape_indir.go b/test/escape_indir.go
index 91aac77..7c06ceb 100644
--- a/test/escape_indir.go
+++ b/test/escape_indir.go
@@ -54,14 +54,14 @@
i := 0 // ERROR "moved to heap: i"
x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap"
x.p = &i // ERROR "&i escapes to heap"
- sink = x
+ sink = x // ERROR "x escapes to heap"
}
func constptr2() {
i := 0 // ERROR "moved to heap: i"
x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
x.p = &i // ERROR "&i escapes to heap"
- sink = *x
+ sink = *x// ERROR "\*x escapes to heap"
}
func constptr4() *ConstPtr {
diff --git a/test/escape_level.go b/test/escape_level.go
index 336321b..581e4a9 100644
--- a/test/escape_level.go
+++ b/test/escape_level.go
@@ -23,7 +23,7 @@
p0 := &i // ERROR "moved to heap: p0" "&i escapes to heap"
p1 := &p0 // ERROR "moved to heap: p1" "&p0 escapes to heap"
p2 := &p1 // ERROR "&p1 escapes to heap"
- sink = p2
+ sink = p2 // ERROR "p2 escapes to heap"
}
func level2() {
@@ -31,7 +31,7 @@
p0 := &i // ERROR "moved to heap: p0" "&i escapes to heap"
p1 := &p0 // ERROR "&p0 escapes to heap"
p2 := &p1 // ERROR "&p1 does not escape"
- sink = *p2
+ sink = *p2 // ERROR "\*p2 escapes to heap"
}
func level3() {
@@ -39,7 +39,7 @@
p0 := &i // ERROR "&i escapes to heap"
p1 := &p0 // ERROR "&p0 does not escape"
p2 := &p1 // ERROR "&p1 does not escape"
- sink = **p2
+ sink = **p2 // ERROR "\* \(\*p2\) escapes to heap"
}
func level4() {
@@ -55,7 +55,7 @@
p0 := &i // ERROR "moved to heap: p0" "&i escapes to heap"
p1 := &p0 // ERROR "&p0 escapes to heap"
p2 := p1
- sink = p2
+ sink = p2 // ERROR "p2 escapes to heap"
}
func level6() {
@@ -63,7 +63,7 @@
p0 := &i // ERROR "&i escapes to heap"
p1 := &p0 // ERROR "&p0 does not escape"
p2 := p1
- sink = *p2
+ sink = *p2 // ERROR "\*p2 escapes to heap"
}
func level7() {
@@ -80,7 +80,7 @@
p0 := &i // ERROR "&i escapes to heap"
p1 := &p0 // ERROR "&p0 does not escape"
p2 := *p1
- sink = p2
+ sink = p2 // ERROR "p2 escapes to heap"
}
func level9() {
@@ -88,7 +88,7 @@
p0 := &i // ERROR "&i does not escape"
p1 := &p0 // ERROR "&p0 does not escape"
p2 := *p1
- sink = *p2
+ sink = *p2 // ERROR "\*p2 escapes to heap"
}
func level10() {
@@ -96,7 +96,7 @@
p0 := &i // ERROR "&i does not escape"
p1 := *p0
p2 := &p1 // ERROR "&p1 does not escape"
- sink = *p2
+ sink = *p2 // ERROR "\*p2 escapes to heap"
}
func level11() {
diff --git a/test/escape_map.go b/test/escape_map.go
index 53fcfdf..868c456 100644
--- a/test/escape_map.go
+++ b/test/escape_map.go
@@ -95,7 +95,7 @@
i := 0 // ERROR "moved to heap: i"
j := 0 // ERROR "moved to heap: j"
m := map[*int]*int{&i: &j} // ERROR "&i escapes to heap" "&j escapes to heap" "literal escapes to heap"
- sink = m
+ sink = m // ERROR "m escapes to heap"
}
func map9() *int {