diff options
author | Colin Cross <ccross@android.com> | 2019-09-07 08:34:44 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2019-09-07 08:34:44 -0700 |
commit | efed63416765c846a4ac234c8386bccfaac45720 (patch) | |
tree | 663855425763eda463086870ddc08606b39338f3 /test | |
parent | 29e948526476872f74f3fa2c9b508cda559cfd12 (diff) | |
download | platform_prebuilts_go_linux-x86-efed63416765c846a4ac234c8386bccfaac45720.tar.gz platform_prebuilts_go_linux-x86-efed63416765c846a4ac234c8386bccfaac45720.tar.bz2 platform_prebuilts_go_linux-x86-efed63416765c846a4ac234c8386bccfaac45720.zip |
Update prebuilts to go 1.13ndk-sysroot-r21
From https://ci.android.com/builds/submitted/5859978/linux/latest/go.zip
Test: m blueprint_tools
Change-Id: Ief07b24cffce02195326d627f28ba879e8f14f6b
Diffstat (limited to 'test')
224 files changed, 11385 insertions, 975 deletions
diff --git a/test/bench/go1/go.mod b/test/bench/go1/go.mod new file mode 100644 index 00000000..41f75c40 --- /dev/null +++ b/test/bench/go1/go.mod @@ -0,0 +1,3 @@ +module test/bench/go1 + +go 1.12 diff --git a/test/blank1.go b/test/blank1.go index bf94d1a0..1a9f0124 100644 --- a/test/blank1.go +++ b/test/blank1.go @@ -7,7 +7,7 @@ // Test that incorrect uses of the blank identifer are caught. // Does not compile. -package _ // ERROR "invalid package name _" +package _ // ERROR "invalid package name" var t struct { _ int @@ -22,8 +22,8 @@ type T struct { } func main() { - _() // ERROR "cannot use _ as value" - x := _+1 // ERROR "cannot use _ as value" + _() // ERROR "cannot use .* as value" + x := _+1 // ERROR "cannot use .* as value" _ = x _ = t._ // ERROR "cannot refer to blank field|invalid use of" diff --git a/test/chan/select8.go b/test/chan/select8.go new file mode 100644 index 00000000..20bca3a0 --- /dev/null +++ b/test/chan/select8.go @@ -0,0 +1,55 @@ +// run + +// Copyright 2019 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 break statements in a select. +// Gccgo had a bug in handling this. +// Test 1,2,3-case selects, so it covers both the general +// code path and the specialized optimizations for one- +// and two-case selects. + +package main + +var ch = make(chan int) + +func main() { + go func() { + for { + ch <- 5 + } + }() + + select { + case <-ch: + break + panic("unreachable") + } + + select { + default: + break + panic("unreachable") + } + + select { + case <-ch: + break + panic("unreachable") + default: + break + panic("unreachable") + } + + select { + case <-ch: + break + panic("unreachable") + case ch <- 10: + panic("unreachable") + default: + break + panic("unreachable") + } +} diff --git a/test/closure3.dir/main.go b/test/closure3.dir/main.go index ae4bef79..3ec90139 100644 --- a/test/closure3.dir/main.go +++ b/test/closure3.dir/main.go @@ -208,7 +208,7 @@ func main() { func() { // ERROR "func literal does not escape" func() { // ERROR "can inline main.func24" a = 2 - }() // ERROR "inlining call to main.func24" "&a does not escape" + }() // ERROR "inlining call to main.func24" }() if a != 2 { ppanic("a != 2") @@ -220,7 +220,7 @@ func main() { func(b int) { // ERROR "func literal does not escape" func() { // ERROR "can inline main.func25.1" b = 3 - }() // ERROR "inlining call to main.func25.1" "&b does not escape" + }() // ERROR "inlining call to main.func25.1" if b != 3 { ppanic("b != 3") } @@ -272,7 +272,7 @@ func main() { a = a * x b = b * y c = c * z - }(10) // ERROR "inlining call to main.func28.1.1" "&a does not escape" "&b does not escape" "&c does not escape" + }(10) // ERROR "inlining call to main.func28.1.1" return a + c }(100) + b }(1000); r != 2350 { diff --git a/test/cmplx.go b/test/cmplx.go index dedf2bd8..d63c7ebc 100644 --- a/test/cmplx.go +++ b/test/cmplx.go @@ -49,10 +49,10 @@ func main() { _ = complex(f64, F64) // ERROR "complex" _ = complex(F64, f64) // ERROR "complex" - _ = complex(F1()) // ERROR "expects two arguments.*returns 1" - _ = complex(F3()) // ERROR "expects two arguments.*returns 3" + _ = complex(F1()) // ERROR "not enough arguments" + _ = complex(F3()) // ERROR "too many arguments" - _ = complex() // ERROR "missing argument" + _ = complex() // ERROR "not enough arguments" c128 = complex(f32, f32) // ERROR "cannot use" c64 = complex(f64, f64) // ERROR "cannot use" diff --git a/test/codegen/alloc.go b/test/codegen/alloc.go new file mode 100644 index 00000000..31455fda --- /dev/null +++ b/test/codegen/alloc.go @@ -0,0 +1,34 @@ +// asmcheck + +// Copyright 2018 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. + +// These tests check that allocating a 0-size object does not +// introduce a call to runtime.newobject. + +package codegen + +func zeroAllocNew1() *struct{} { + // 386:-`CALL\truntime\.newobject` + // amd64:-`CALL\truntime\.newobject` + // arm:-`CALL\truntime\.newobject` + // arm64:-`CALL\truntime\.newobject` + return new(struct{}) +} + +func zeroAllocNew2() *[0]int { + // 386:-`CALL\truntime\.newobject` + // amd64:-`CALL\truntime\.newobject` + // arm:-`CALL\truntime\.newobject` + // arm64:-`CALL\truntime\.newobject` + return new([0]int) +} + +func zeroAllocSliceLit() []int { + // 386:-`CALL\truntime\.newobject` + // amd64:-`CALL\truntime\.newobject` + // arm:-`CALL\truntime\.newobject` + // arm64:-`CALL\truntime\.newobject` + return []int{} +} diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index e5671774..dcbc6d3f 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -15,6 +15,7 @@ package codegen // ----------------- // var ef int + func SubMem(arr []int, b, c, d int) int { // 386:`SUBL\s[A-Z]+,\s8\([A-Z]+\)` // amd64:`SUBQ\s[A-Z]+,\s16\([A-Z]+\)` @@ -175,15 +176,28 @@ func Pow2Mods(n1 uint, n2 int) (uint, int) { // ppc64le:"ANDCC\t[$]31" a := n1 % 32 // unsigned - // 386:-"IDIVL" - // amd64:-"IDIVQ" - // arm:-".*udiv" - // arm64:-"REM" + // 386:"SHRL",-"IDIVL" + // amd64:"SHRQ",-"IDIVQ" + // arm:"SRA",-".*udiv" + // arm64:"ASR",-"REM" + // ppc64:"SRAD" + // ppc64le:"SRAD" b := n2 % 64 // signed return a, b } +// Check that signed divisibility checks get converted to AND on low bits +func Pow2DivisibleSigned(n int) bool { + // 386:"TESTL\t[$]63",-"DIVL",-"SHRL" + // amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ" + // arm:"AND\t[$]63",-".*udiv",-"SRA" + // arm64:"AND\t[$]63",-"UDIV",-"ASR" + // ppc64:"ANDCC\t[$]63",-"SRAD" + // ppc64le:"ANDCC\t[$]63",-"SRAD" + return n%64 == 0 // signed +} + // Check that constant modulo divs get turned into MULs func ConstMods(n1 uint, n2 int) (uint, int) { // amd64:"MOVQ\t[$]-1085102592571150095","MULQ",-"DIVQ" @@ -201,6 +215,43 @@ func ConstMods(n1 uint, n2 int) (uint, int) { return a, b } +// Check that divisibility checks x%c==0 are converted to MULs and rotates +func Divisible(n1 uint, n2 int) (bool, bool, bool, bool) { + // amd64:"MOVQ\t[$]-6148914691236517205","IMULQ","ROLQ\t[$]63",-"DIVQ" + // 386:"IMUL3L\t[$]-1431655765","ROLL\t[$]31",-"DIVQ" + // arm64:"MOVD\t[$]-6148914691236517205","MUL","ROR",-"DIV" + // arm:"MUL","CMP\t[$]715827882",-".*udiv" + // ppc64:"MULLD","ROTL\t[$]63" + // ppc64le:"MULLD","ROTL\t[$]63" + evenU := n1%6 == 0 + + // amd64:"MOVQ\t[$]-8737931403336103397","IMULQ",-"ROLQ",-"DIVQ" + // 386:"IMUL3L\t[$]678152731",-"ROLL",-"DIVQ" + // arm64:"MOVD\t[$]-8737931403336103397","MUL",-"ROR",-"DIV" + // arm:"MUL","CMP\t[$]226050910",-".*udiv" + // ppc64:"MULLD",-"ROTL" + // ppc64le:"MULLD",-"ROTL" + oddU := n1%19 == 0 + + // amd64:"IMULQ","ADD","ROLQ\t[$]63",-"DIVQ" + // 386:"IMUL3L\t[$]-1431655765","ADDL\t[$]715827882","ROLL\t[$]31",-"DIVQ" + // arm64:"MUL","ADD\t[$]3074457345618258602","ROR",-"DIV" + // arm:"MUL","ADD\t[$]715827882",-".*udiv" + // ppc64:"MULLD","ADD","ROTL\t[$]63" + // ppc64le:"MULLD","ADD","ROTL\t[$]63" + evenS := n2%6 == 0 + + // amd64:"IMULQ","ADD",-"ROLQ",-"DIVQ" + // 386:"IMUL3L\t[$]678152731","ADDL\t[$]113025455",-"ROLL",-"DIVQ" + // arm64:"MUL","ADD\t[$]485440633518672410",-"ROR",-"DIV" + // arm:"MUL","ADD\t[$]113025455",-".*udiv" + // ppc64:"MULLD","ADD",-"ROTL" + // ppc64le:"MULLD","ADD",-"ROTL" + oddS := n2%19 == 0 + + return evenU, oddU, evenS, oddS +} + // Check that fix-up code is not generated for divisions where it has been proven that // that the divisor is not -1 or that the dividend is > MinIntNN. func NoFix64A(divr int64) (int64, int64) { @@ -380,3 +431,13 @@ func MULS(a, b, c uint32) (uint32, uint32, uint32) { r2 := c - b*64 return r0, r1, r2 } + +func addSpecial(a, b, c uint32) (uint32, uint32, uint32) { + // amd64:`INCL` + a++ + // amd64:`DECL` + b-- + // amd64:`SUBL.*-128` + c += 128 + return a, b, c +} diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index f14918e9..62ba184e 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -215,30 +215,30 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 { // ppc64:"ANDCC",-"CMPW" // ppc64le:"ANDCC",-"CMPW" - if a & 63 == 0 { + if a&63 == 0 { return 1 } // ppc64:"ANDCC",-"CMP" // ppc64le:"ANDCC",-"CMP" - if d & 255 == 0 { + if d&255 == 0 { return 1 } // ppc64:"ANDCC",-"CMP" // ppc64le:"ANDCC",-"CMP" - if d & e == 0 { + if d&e == 0 { return 1 } // ppc64:"ORCC",-"CMP" // ppc64le:"ORCC",-"CMP" - if d | e == 0 { + if d|e == 0 { return 1 } // ppc64:"XORCC",-"CMP" // ppc64le:"XORCC",-"CMP" - if e ^ d == 0 { + if e^d == 0 { return 1 } return 0 diff --git a/test/codegen/condmove.go b/test/codegen/condmove.go index aa82d43f..3690a546 100644 --- a/test/codegen/condmove.go +++ b/test/codegen/condmove.go @@ -95,7 +95,7 @@ func cmovfloatint2(x, y float64) float64 { rexp = rexp - 1 } // amd64:"CMOVQHI" - // arm64:"CSEL\tGT" + // arm64:"CSEL\tMI" r = r - ldexp(y, (rexp-yexp)) } return r diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 5e1f60b0..7ec36549 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -117,6 +117,11 @@ func FusedSub64_b(x, y, z float64) float64 { return z - x*y } +func Cmp(f float64) bool { + // arm64:"FCMPD","BLE",-"CSET\tGT",-"CBZ" + return f > 4 || f < -4 +} + // ---------------- // // Non-floats // // ---------------- // diff --git a/test/codegen/issue31618.go b/test/codegen/issue31618.go new file mode 100644 index 00000000..8effe299 --- /dev/null +++ b/test/codegen/issue31618.go @@ -0,0 +1,22 @@ +// asmcheck + +// Copyright 2019 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. + +package codegen + +// Make sure we remove both inline marks in the following code. +// Both +5 and +6 should map to real instructions, which can +// be used as inline marks instead of explicit nops. +func f(x int) int { + // amd64:-"XCHGL" + x = g(x) + 5 + // amd64:-"XCHGL" + x = g(x) + 6 + return x +} + +func g(x int) int { + return x >> 3 +} diff --git a/test/codegen/math.go b/test/codegen/math.go index aaf6b080..597271ce 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -15,12 +15,14 @@ func approx(x float64) { // arm64:"FRINTPD" // ppc64:"FRIP" // ppc64le:"FRIP" + // wasm:"F64Ceil" sink64[0] = math.Ceil(x) // s390x:"FIDBR\t[$]7" // arm64:"FRINTMD" // ppc64:"FRIM" // ppc64le:"FRIM" + // wasm:"F64Floor" sink64[1] = math.Floor(x) // s390x:"FIDBR\t[$]1" @@ -33,10 +35,12 @@ func approx(x float64) { // arm64:"FRINTZD" // ppc64:"FRIZ" // ppc64le:"FRIZ" + // wasm:"F64Trunc" sink64[3] = math.Trunc(x) // s390x:"FIDBR\t[$]4" // arm64:"FRINTND" + // wasm:"F64Nearest" sink64[4] = math.RoundToEven(x) } @@ -47,6 +51,7 @@ func sqrt(x float64) float64 { // arm/7:"SQRTD" // mips/hardfloat:"SQRTD" mips/softfloat:-"SQRTD" // mips64/hardfloat:"SQRTD" mips64/softfloat:-"SQRTD" + // wasm:"F64Sqrt" return math.Sqrt(x) } @@ -57,6 +62,7 @@ func abs(x, y float64) { // s390x:"LPDFR\t",-"MOVD\t" (no integer load/store) // ppc64:"FABS\t" // ppc64le:"FABS\t" + // wasm:"F64Abs" sink64[0] = math.Abs(x) // amd64:"BTRQ\t[$]63","PXOR" (TODO: this should be BTSQ) @@ -78,6 +84,7 @@ func copysign(a, b, c float64) { // s390x:"CPSDR",-"MOVD" (no integer load/store) // ppc64:"FCPSGN" // ppc64le:"FCPSGN" + // wasm:"F64Copysign" sink64[0] = math.Copysign(a, b) // amd64:"BTSQ\t[$]63" diff --git a/test/codegen/mathbits.go b/test/codegen/mathbits.go index 44ab2c02..0d94bd1b 100644 --- a/test/codegen/mathbits.go +++ b/test/codegen/mathbits.go @@ -17,6 +17,7 @@ func LeadingZeros(n uint) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.LeadingZeros(n) } @@ -25,14 +26,16 @@ func LeadingZeros64(n uint64) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.LeadingZeros64(n) } func LeadingZeros32(n uint32) int { // amd64:"BSRQ","LEAQ",-"CMOVQEQ" // s390x:"FLOGR" - // arm:"CLZ" arm64:"CLZ" + // arm:"CLZ" arm64:"CLZW" // mips:"CLZ" + // wasm:"I64Clz" return bits.LeadingZeros32(n) } @@ -41,6 +44,7 @@ func LeadingZeros16(n uint16) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.LeadingZeros16(n) } @@ -49,6 +53,7 @@ func LeadingZeros8(n uint8) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.LeadingZeros8(n) } @@ -61,6 +66,7 @@ func Len(n uint) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.Len(n) } @@ -69,6 +75,7 @@ func Len64(n uint64) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.Len64(n) } @@ -77,6 +84,7 @@ func Len32(n uint32) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.Len32(n) } @@ -85,6 +93,7 @@ func Len16(n uint16) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.Len16(n) } @@ -93,6 +102,7 @@ func Len8(n uint8) int { // s390x:"FLOGR" // arm:"CLZ" arm64:"CLZ" // mips:"CLZ" + // wasm:"I64Clz" return bits.Len8(n) } @@ -106,6 +116,7 @@ func OnesCount(n uint) int { // s390x:"POPCNT" // ppc64:"POPCNTD" // ppc64le:"POPCNTD" + // wasm:"I64Popcnt" return bits.OnesCount(n) } @@ -115,6 +126,7 @@ func OnesCount64(n uint64) int { // s390x:"POPCNT" // ppc64:"POPCNTD" // ppc64le:"POPCNTD" + // wasm:"I64Popcnt" return bits.OnesCount64(n) } @@ -124,6 +136,7 @@ func OnesCount32(n uint32) int { // s390x:"POPCNT" // ppc64:"POPCNTW" // ppc64le:"POPCNTW" + // wasm:"I64Popcnt" return bits.OnesCount32(n) } @@ -133,6 +146,7 @@ func OnesCount16(n uint16) int { // s390x:"POPCNT" // ppc64:"POPCNTW" // ppc64le:"POPCNTW" + // wasm:"I64Popcnt" return bits.OnesCount16(n) } @@ -140,6 +154,7 @@ func OnesCount8(n uint8) int { // s390x:"POPCNT" // ppc64:"POPCNTB" // ppc64le:"POPCNTB" + // wasm:"I64Popcnt" return bits.OnesCount8(n) } @@ -170,6 +185,10 @@ func ReverseBytes32(n uint32) uint32 { func ReverseBytes16(n uint16) uint16 { // amd64:"ROLW" + // arm64:"REV16W",-"UBFX",-"ORR" + // arm/5:"SLL","SRL","ORR" + // arm/6:"REV16" + // arm/7:"REV16" return bits.ReverseBytes16(n) } @@ -183,6 +202,7 @@ func RotateLeft64(n uint64) uint64 { // ppc64:"ROTL" // ppc64le:"ROTL" // s390x:"RLLG" + // wasm:"I64Rotl" return bits.RotateLeft64(n, 37) } @@ -238,39 +258,61 @@ func RotateLeftVariable32(n uint32, m int) uint32 { func TrailingZeros(n uint) int { // amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ" + // arm:"CLZ" + // arm64:"RBIT","CLZ" // s390x:"FLOGR" - // ppc64:"ANDN","POPCNTD" - // ppc64le:"ANDN","POPCNTD" + // ppc64/power8:"ANDN","POPCNTD" + // ppc64le/power8:"ANDN","POPCNTD" + // ppc64/power9: "CNTTZD" + // ppc64le/power9: "CNTTZD" + // wasm:"I64Ctz" return bits.TrailingZeros(n) } func TrailingZeros64(n uint64) int { // amd64:"BSFQ","MOVL\t\\$64","CMOVQEQ" + // arm64:"RBIT","CLZ" // s390x:"FLOGR" - // ppc64:"ANDN","POPCNTD" - // ppc64le:"ANDN","POPCNTD" + // ppc64/power8:"ANDN","POPCNTD" + // ppc64le/power8:"ANDN","POPCNTD" + // ppc64/power9: "CNTTZD" + // ppc64le/power9: "CNTTZD" + // wasm:"I64Ctz" return bits.TrailingZeros64(n) } func TrailingZeros32(n uint32) int { // amd64:"BTSQ\\t\\$32","BSFQ" + // arm:"CLZ" + // arm64:"RBITW","CLZW" // s390x:"FLOGR","MOVWZ" - // ppc64:"ANDN","POPCNTW" - // ppc64le:"ANDN","POPCNTW" + // ppc64/power8:"ANDN","POPCNTW" + // ppc64le/power8:"ANDN","POPCNTW" + // ppc64/power9: "CNTTZW" + // ppc64le/power9: "CNTTZW" + // wasm:"I64Ctz" return bits.TrailingZeros32(n) } func TrailingZeros16(n uint16) int { // amd64:"BSFL","BTSL\\t\\$16" + // arm:"ORR\t\\$65536","CLZ",-"MOVHU\tR" + // arm64:"ORR\t\\$65536","RBITW","CLZW",-"MOVHU\tR",-"RBIT\t",-"CLZ\t" // s390x:"FLOGR","OR\t\\$65536" - // ppc64:"POPCNTD","OR\\t\\$65536" - // ppc64le:"POPCNTD","OR\\t\\$65536" + // ppc64/power8:"POPCNTD","OR\\t\\$65536" + // ppc64le/power8:"POPCNTD","OR\\t\\$65536" + // ppc64/power9:"CNTTZD","OR\\t\\$65536" + // ppc64le/power9:"CNTTZD","OR\\t\\$65536" + // wasm:"I64Ctz" return bits.TrailingZeros16(n) } func TrailingZeros8(n uint8) int { // amd64:"BSFL","BTSL\\t\\$8" + // arm:"ORR\t\\$256","CLZ",-"MOVBU\tR" + // arm64:"ORR\t\\$256","RBITW","CLZW",-"MOVBU\tR",-"RBIT\t",-"CLZ\t" // s390x:"FLOGR","OR\t\\$256" + // wasm:"I64Ctz" return bits.TrailingZeros8(n) } @@ -310,6 +352,7 @@ func IterateBits16(n uint16) int { i := 0 for n != 0 { // amd64:"BSFL",-"BTSL" + // arm64:"RBITW","CLZW",-"ORR" i += bits.TrailingZeros16(n) n &= n - 1 } @@ -320,6 +363,7 @@ func IterateBits8(n uint8) int { i := 0 for n != 0 { // amd64:"BSFL",-"BTSL" + // arm64:"RBITW","CLZW",-"ORR" i += bits.TrailingZeros8(n) n &= n - 1 } @@ -331,57 +375,88 @@ func IterateBits8(n uint8) int { // --------------- // func Add(x, y, ci uint) (r, co uint) { + // arm64:"ADDS","ADCS","ADC",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ","SBBQ","NEGQ" + // s390x:"ADDE","ADDC\t[$]-1," return bits.Add(x, y, ci) } func AddC(x, ci uint) (r, co uint) { + // arm64:"ADDS","ADCS","ADC",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ","SBBQ","NEGQ" + // s390x:"ADDE","ADDC\t[$]-1," return bits.Add(x, 7, ci) } func AddZ(x, y uint) (r, co uint) { + // arm64:"ADDS","ADC",-"ADCS",-"ADD\t",-"CMP" // amd64:"ADDQ","SBBQ","NEGQ",-"NEGL",-"ADCQ" + // s390x:"ADDC",-"ADDC\t[$]-1," return bits.Add(x, y, 0) } func AddR(x, y, ci uint) uint { + // arm64:"ADDS","ADCS",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ",-"SBBQ",-"NEGQ" + // s390x:"ADDE","ADDC\t[$]-1," r, _ := bits.Add(x, y, ci) return r } + func AddM(p, q, r *[3]uint) { var c uint r[0], c = bits.Add(p[0], q[0], c) + // arm64:"ADCS",-"ADD\t",-"CMP" // amd64:"ADCQ",-"NEGL",-"SBBQ",-"NEGQ" + // s390x:"ADDE",-"ADDC\t[$]-1," r[1], c = bits.Add(p[1], q[1], c) r[2], c = bits.Add(p[2], q[2], c) } func Add64(x, y, ci uint64) (r, co uint64) { + // arm64:"ADDS","ADCS","ADC",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ","SBBQ","NEGQ" + // ppc64: "ADDC", "ADDE", "ADDZE" + // ppc64le: "ADDC", "ADDE", "ADDZE" + // s390x:"ADDE","ADDC\t[$]-1," return bits.Add64(x, y, ci) } func Add64C(x, ci uint64) (r, co uint64) { + // arm64:"ADDS","ADCS","ADC",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ","SBBQ","NEGQ" + // ppc64: "ADDC", "ADDE", "ADDZE" + // ppc64le: "ADDC", "ADDE", "ADDZE" + // s390x:"ADDE","ADDC\t[$]-1," return bits.Add64(x, 7, ci) } func Add64Z(x, y uint64) (r, co uint64) { + // arm64:"ADDS","ADC",-"ADCS",-"ADD\t",-"CMP" // amd64:"ADDQ","SBBQ","NEGQ",-"NEGL",-"ADCQ" + // ppc64: "ADDC", "ADDE", "ADDZE" + // ppc64le: "ADDC", "ADDE", "ADDZE" + // s390x:"ADDC",-"ADDC\t[$]-1," return bits.Add64(x, y, 0) } func Add64R(x, y, ci uint64) uint64 { + // arm64:"ADDS","ADCS",-"ADD\t",-"CMP" // amd64:"NEGL","ADCQ",-"SBBQ",-"NEGQ" + // ppc64: "ADDC", "ADDE", "ADDZE" + // ppc64le: "ADDC", "ADDE", "ADDZE" + // s390x:"ADDE","ADDC\t[$]-1," r, _ := bits.Add64(x, y, ci) return r } func Add64M(p, q, r *[3]uint64) { var c uint64 r[0], c = bits.Add64(p[0], q[0], c) + // arm64:"ADCS",-"ADD\t",-"CMP" // amd64:"ADCQ",-"NEGL",-"SBBQ",-"NEGQ" + // ppc64: "ADDC", "ADDE", "ADDZE" + // ppc64le: "ADDC", "ADDE", "ADDZE" + // s390x:"ADDE",-"ADDC\t[$]-1," r[1], c = bits.Add64(p[1], q[1], c) r[2], c = bits.Add64(p[2], q[2], c) } @@ -392,21 +467,29 @@ func Add64M(p, q, r *[3]uint64) { func Sub(x, y, ci uint) (r, co uint) { // amd64:"NEGL","SBBQ","NEGQ" + // arm64:"NEGS","SBCS","NGC","NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" return bits.Sub(x, y, ci) } func SubC(x, ci uint) (r, co uint) { // amd64:"NEGL","SBBQ","NEGQ" + // arm64:"NEGS","SBCS","NGC","NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" return bits.Sub(x, 7, ci) } func SubZ(x, y uint) (r, co uint) { // amd64:"SUBQ","SBBQ","NEGQ",-"NEGL" + // arm64:"SUBS","NGC","NEG",-"SBCS",-"ADD",-"SUB\t",-"CMP" + // s390x:"SUBC" return bits.Sub(x, y, 0) } func SubR(x, y, ci uint) uint { // amd64:"NEGL","SBBQ",-"NEGQ" + // arm64:"NEGS","SBCS",-"NGC",-"NEG\t",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" r, _ := bits.Sub(x, y, ci) return r } @@ -414,27 +497,37 @@ func SubM(p, q, r *[3]uint) { var c uint r[0], c = bits.Sub(p[0], q[0], c) // amd64:"SBBQ",-"NEGL",-"NEGQ" + // arm64:"SBCS",-"NEGS",-"NGC",-"NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" r[1], c = bits.Sub(p[1], q[1], c) r[2], c = bits.Sub(p[2], q[2], c) } func Sub64(x, y, ci uint64) (r, co uint64) { // amd64:"NEGL","SBBQ","NEGQ" + // arm64:"NEGS","SBCS","NGC","NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" return bits.Sub64(x, y, ci) } func Sub64C(x, ci uint64) (r, co uint64) { // amd64:"NEGL","SBBQ","NEGQ" + // arm64:"NEGS","SBCS","NGC","NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" return bits.Sub64(x, 7, ci) } func Sub64Z(x, y uint64) (r, co uint64) { // amd64:"SUBQ","SBBQ","NEGQ",-"NEGL" + // arm64:"SUBS","NGC","NEG",-"SBCS",-"ADD",-"SUB\t",-"CMP" + // s390x:"SUBC" return bits.Sub64(x, y, 0) } func Sub64R(x, y, ci uint64) uint64 { // amd64:"NEGL","SBBQ",-"NEGQ" + // arm64:"NEGS","SBCS",-"NGC",-"NEG\t",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" r, _ := bits.Sub64(x, y, ci) return r } @@ -442,6 +535,8 @@ func Sub64M(p, q, r *[3]uint64) { var c uint64 r[0], c = bits.Sub64(p[0], q[0], c) // amd64:"SBBQ",-"NEGL",-"NEGQ" + // arm64:"SBCS",-"NEGS",-"NGC",-"NEG",-"ADD",-"SUB",-"CMP" + // s390x:"SUBE" r[1], c = bits.Sub64(p[1], q[1], c) r[2], c = bits.Sub64(p[2], q[2], c) } @@ -475,7 +570,17 @@ func Div(hi, lo, x uint) (q, r uint) { return bits.Div(hi, lo, x) } +func Div32(hi, lo, x uint32) (q, r uint32) { + // arm64:"ORR","UDIV","MSUB",-"UREM" + return bits.Div32(hi, lo, x) +} + func Div64(hi, lo, x uint64) (q, r uint64) { // amd64:"DIVQ" return bits.Div64(hi, lo, x) } + +func Div64degenerate(x uint64) (q, r uint64) { + // amd64:-"DIVQ" + return bits.Div64(0, x, 5) +} diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index b3d2cb20..747e2300 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -20,7 +20,7 @@ var sink16 uint16 // ------------- // func load_le64(b []byte) { - // amd64:`MOVQ\s\(.*\),` + // amd64:`MOVQ\s\(.*\),`,-`MOV[BWL]\t[^$]`,-`OR` // s390x:`MOVDBR\s\(.*\),` // arm64:`MOVD\s\(R[0-9]+\),`,-`MOV[BHW]` // ppc64le:`MOVD\s`,-`MOV[BHW]Z` @@ -28,7 +28,7 @@ func load_le64(b []byte) { } func load_le64_idx(b []byte, idx int) { - // amd64:`MOVQ\s\(.*\)\(.*\*1\),` + // amd64:`MOVQ\s\(.*\)\(.*\*1\),`,-`MOV[BWL]\t[^$]`,-`OR` // s390x:`MOVDBR\s\(.*\)\(.*\*1\),` // arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[BHW]` // ppc64le:`MOVD\s`,-`MOV[BHW]Z\s` @@ -36,76 +36,78 @@ func load_le64_idx(b []byte, idx int) { } func load_le32(b []byte) { - // amd64:`MOVL\s\(.*\),` 386:`MOVL\s\(.*\),` + // amd64:`MOVL\s\(.*\),`,-`MOV[BW]`,-`OR` + // 386:`MOVL\s\(.*\),`,-`MOV[BW]`,-`OR` // s390x:`MOVWBR\s\(.*\),` // arm64:`MOVWU\s\(R[0-9]+\),`,-`MOV[BH]` - // ppc64le:`MOVWZ\s` + // ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s` sink32 = binary.LittleEndian.Uint32(b) } func load_le32_idx(b []byte, idx int) { - // amd64:`MOVL\s\(.*\)\(.*\*1\),` 386:`MOVL\s\(.*\)\(.*\*1\),` + // amd64:`MOVL\s\(.*\)\(.*\*1\),`,-`MOV[BW]`,-`OR` + // 386:`MOVL\s\(.*\)\(.*\*1\),`,-`MOV[BW]`,-`OR` // s390x:`MOVWBR\s\(.*\)\(.*\*1\),` // arm64:`MOVWU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[BH]` - // ppc64le:`MOVWZ\s` + // ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s` sink32 = binary.LittleEndian.Uint32(b[idx:]) } func load_le16(b []byte) { - // amd64:`MOVWLZX\s\(.*\),` - // ppc64le:`MOVHZ\s` + // amd64:`MOVWLZX\s\(.*\),`,-`MOVB`,-`OR` + // ppc64le:`MOVHZ\s`,-`MOVBZ` // arm64:`MOVHU\s\(R[0-9]+\),`,-`MOVB` sink16 = binary.LittleEndian.Uint16(b) } func load_le16_idx(b []byte, idx int) { - // amd64:`MOVWLZX\s\(.*\),` - // ppc64le:`MOVHZ\s` + // amd64:`MOVWLZX\s\(.*\),`,-`MOVB`,-`OR` + // ppc64le:`MOVHZ\s`,-`MOVBZ` // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOVB` sink16 = binary.LittleEndian.Uint16(b[idx:]) } func load_be64(b []byte) { - // amd64:`BSWAPQ` + // amd64:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR` // s390x:`MOVD\s\(.*\),` // arm64:`REV`,`MOVD\s\(R[0-9]+\),`,-`MOV[BHW]`,-`REVW`,-`REV16W` - // ppc64le:`MOVDBR` + // ppc64le:`MOVDBR`,-`MOV[BHW]Z` sink64 = binary.BigEndian.Uint64(b) } func load_be64_idx(b []byte, idx int) { - // amd64:`BSWAPQ` + // amd64:`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR` // s390x:`MOVD\s\(.*\)\(.*\*1\),` // arm64:`REV`,`MOVD\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[WHB]`,-`REVW`,-`REV16W` - // ppc64le:`MOVDBR` + // ppc64le:`MOVDBR`,-`MOV[BHW]Z` sink64 = binary.BigEndian.Uint64(b[idx:]) } func load_be32(b []byte) { - // amd64:`BSWAPL` + // amd64:`BSWAPL`,-`MOV[BW]`,-`OR` // s390x:`MOVWZ\s\(.*\),` // arm64:`REVW`,`MOVWU\s\(R[0-9]+\),`,-`MOV[BH]`,-`REV16W` - // ppc64le:`MOVWBR` + // ppc64le:`MOVWBR`,-`MOV[BH]Z` sink32 = binary.BigEndian.Uint32(b) } func load_be32_idx(b []byte, idx int) { - // amd64:`BSWAPL` + // amd64:`BSWAPL`,-`MOV[BW]`,-`OR` // s390x:`MOVWZ\s\(.*\)\(.*\*1\),` // arm64:`REVW`,`MOVWU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[HB]`,-`REV16W` - // ppc64le:`MOVWBR` + // ppc64le:`MOVWBR`,-`MOV[BH]Z` sink32 = binary.BigEndian.Uint32(b[idx:]) } func load_be16(b []byte) { - // amd64:`ROLW\s\$8` + // amd64:`ROLW\s\$8`,-`MOVB`,-`OR` // arm64:`REV16W`,`MOVHU\s\(R[0-9]+\),`,-`MOVB` // ppc64le:`MOVHBR` sink16 = binary.BigEndian.Uint16(b) } func load_be16_idx(b []byte, idx int) { - // amd64:`ROLW\s\$8` + // amd64:`ROLW\s\$8`,-`MOVB`,-`OR` // arm64:`REV16W`,`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOVB` // ppc64le:`MOVHBR` sink16 = binary.BigEndian.Uint16(b[idx:]) @@ -113,22 +115,25 @@ func load_be16_idx(b []byte, idx int) { func load_le_byte2_uint16(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,-`ORR`,-`MOVB` - // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` + // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // ppc64le:`MOVHZ\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[0]) | uint16(s[1])<<8 } func load_le_byte2_uint16_inv(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,-`ORR`,-`MOVB` - // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` + // 386:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // ppc64le:`MOVHZ\t\(R[0-9]+\)`,-`MOVDZ` return uint16(s[1])<<8 | uint16(s[0]) } func load_le_byte4_uint32(s []byte) uint32 { // arm64:`MOVWU\t\(R[0-9]+\)`,-`ORR`,-`MOV[BH]` - // 386:`MOVL\s\([A-Z]+\)`,-`MOVB`,-`OR`-`MOVW` - // amd64:`MOVL\s\([A-Z]+\)`,-`MOVB`,-`OR`-`MOVW` + // 386:`MOVL\s\([A-Z]+\)`,-`MOV[BW]`,-`OR` + // amd64:`MOVL\s\([A-Z]+\)`,-`MOV[BW]`,-`OR` + // ppc64le:`MOVWZ\t\(R[0-9]+\)`,-`MOV[BH]Z` return uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 | uint32(s[3])<<24 } @@ -139,25 +144,27 @@ func load_le_byte4_uint32_inv(s []byte) uint32 { func load_le_byte8_uint64(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,-`ORR`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+` + // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,-`MOV[BWL]\t[^$]`,-`OR` + // ppc64le:`MOVD\t\(R[0-9]+\)`,-`MOV[BHW]Z` return uint64(s[0]) | uint64(s[1])<<8 | uint64(s[2])<<16 | uint64(s[3])<<24 | uint64(s[4])<<32 | uint64(s[5])<<40 | uint64(s[6])<<48 | uint64(s[7])<<56 } func load_le_byte8_uint64_inv(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,-`ORR`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+` return uint64(s[7])<<56 | uint64(s[6])<<48 | uint64(s[5])<<40 | uint64(s[4])<<32 | uint64(s[3])<<24 | uint64(s[2])<<16 | uint64(s[1])<<8 | uint64(s[0]) } func load_be_byte2_uint16(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` + // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[0])<<8 | uint16(s[1]) } func load_be_byte2_uint16_inv(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`ORL` + // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[1]) | uint16(s[0])<<8 } @@ -168,39 +175,40 @@ func load_be_byte4_uint32(s []byte) uint32 { func load_be_byte4_uint32_inv(s []byte) uint32 { // arm64:`MOVWU\t\(R[0-9]+\)`,`REVW`,-`ORR`,-`REV16W`,-`MOV[BH]` - // amd64:`MOVL\s\([A-Z]+\)`,-`MOVB`,-`OR`,-`MOVW` + // amd64:`MOVL\s\([A-Z]+\)`,-`MOV[BW]`,-`OR` return uint32(s[3]) | uint32(s[2])<<8 | uint32(s[1])<<16 | uint32(s[0])<<24 } func load_be_byte8_uint64(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,`REV`,-`ORR`,-`REVW`,-`REV16W`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+` + // ppc64le:`MOVDBR\t\(R[0-9]+\)`,-`MOV[BHW]Z` return uint64(s[0])<<56 | uint64(s[1])<<48 | uint64(s[2])<<40 | uint64(s[3])<<32 | uint64(s[4])<<24 | uint64(s[5])<<16 | uint64(s[6])<<8 | uint64(s[7]) } func load_be_byte8_uint64_inv(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,`REV`,-`ORR`,-`REVW`,-`REV16W`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+` + // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,-`MOV[BWL]\t[^$]`,-`OR` + // ppc64le:`MOVDBR\t\(R[0-9]+\)`,-`MOV[BHW]Z` return uint64(s[7]) | uint64(s[6])<<8 | uint64(s[5])<<16 | uint64(s[4])<<24 | uint64(s[3])<<32 | uint64(s[2])<<40 | uint64(s[1])<<48 | uint64(s[0])<<56 } func load_le_byte2_uint16_idx(s []byte, idx int) uint16 { // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOVB` // 386:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`ORL`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`OR`,-`MOVB` + // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`MOVB`,-`OR` return uint16(s[idx]) | uint16(s[idx+1])<<8 } func load_le_byte2_uint16_idx_inv(s []byte, idx int) uint16 { // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOVB` // 386:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`ORL`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`OR`,-`MOVB` + // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`MOVB`,-`OR` return uint16(s[idx+1])<<8 | uint16(s[idx]) } func load_le_byte4_uint32_idx(s []byte, idx int) uint32 { // arm64:`MOVWU\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOV[BH]` - // amd64:`MOVL\s\([A-Z]+\)\([A-Z]+`,-`OR`,-`MOVB`,-`MOVW` + // amd64:`MOVL\s\([A-Z]+\)\([A-Z]+`,-`MOV[BW]`,-`OR` return uint32(s[idx]) | uint32(s[idx+1])<<8 | uint32(s[idx+2])<<16 | uint32(s[idx+3])<<24 } @@ -211,7 +219,7 @@ func load_le_byte4_uint32_idx_inv(s []byte, idx int) uint32 { func load_le_byte8_uint64_idx(s []byte, idx int) uint64 { // arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\)`,-`ORR`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\)\([A-Z]+` + // amd64:`MOVQ\s\([A-Z]+\)\([A-Z]+`,-`MOV[BWL]`,-`OR` return uint64(s[idx]) | uint64(s[idx+1])<<8 | uint64(s[idx+2])<<16 | uint64(s[idx+3])<<24 | uint64(s[idx+4])<<32 | uint64(s[idx+5])<<40 | uint64(s[idx+6])<<48 | uint64(s[idx+7])<<56 } @@ -222,13 +230,13 @@ func load_le_byte8_uint64_idx_inv(s []byte, idx int) uint64 { func load_be_byte2_uint16_idx(s []byte, idx int) uint16 { // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`OR`,-`MOVB` + // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`MOVB`,-`OR` return uint16(s[idx])<<8 | uint16(s[idx+1]) } func load_be_byte2_uint16_idx_inv(s []byte, idx int) uint16 { // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`OR`,-`MOVB` + // amd64:`MOVWLZX\s\([A-Z]+\)\([A-Z]+`,-`MOVB`,-`OR` return uint16(s[idx+1]) | uint16(s[idx])<<8 } diff --git a/test/codegen/noextend.go b/test/codegen/noextend.go index 46bfe3f2..424fd200 100644 --- a/test/codegen/noextend.go +++ b/test/codegen/noextend.go @@ -31,30 +31,30 @@ func set16(x8 int8, u8 uint8, y8 int8, z8 uint8) { // AND not needed due to size // ppc64:-"ANDCC" - // ppc64le:-"ANDCC" - sval16[1] = 255 & int16(x8+y8) + // ppc64le:-"ANDCC" + sval16[1] = 255 & int16(x8+y8) // ppc64:-"ANDCC" - // ppc64le:-"ANDCC" - val16[1] = 255 & uint16(u8+z8) + // ppc64le:-"ANDCC" + val16[1] = 255 & uint16(u8+z8) } func shiftidx(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) { // ppc64:-"MOVB\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" - sval16[0] = int16(val16[x8>>1]) + // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" + sval16[0] = int16(val16[x8>>1]) // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" - val16[0] = uint16(sval16[u8>>2]) + // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" + val16[0] = uint16(sval16[u8>>2]) // ppc64:-"MOVH\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" - sval16[1] = int16(val16[x16>>1]) + // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" + sval16[1] = int16(val16[x16>>1]) // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" - val16[1] = uint16(sval16[u16>>2]) + // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" + val16[1] = uint16(sval16[u16>>2]) } @@ -72,11 +72,11 @@ func setnox(x8 int8, u8 uint8, y8 int8, z8 uint8, x16 int16, u16 uint16, x32 int // AND not needed due to size // ppc64:-"ANDCC" // ppc64le:-"ANDCC" - sval16[1] = 255 & int16(x8+y8) + sval16[1] = 255 & int16(x8+y8) // ppc64:-"ANDCC" - // ppc64le:-"ANDCC" - val16[1] = 255 & uint16(u8+z8) + // ppc64le:-"ANDCC" + val16[1] = 255 & uint16(u8+z8) // ppc64:-"MOVB\tR\\d+,\\sR\\d+" // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" @@ -95,24 +95,24 @@ func setnox(x8 int8, u8 uint8, y8 int8, z8 uint8, x16 int16, u16 uint16, x32 int val32[1] = uint32(u16) // ppc64:-"MOVB\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" - sval64[0] = int64(x8) + // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" + sval64[0] = int64(x8) // ppc64:-"MOVH\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" - sval64[1] = int64(x16) + // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" + sval64[1] = int64(x16) // ppc64:-"MOVW\tR\\d+,\\sR\\d+" // ppc64le:-"MOVW\tR\\d+,\\sR\\d+" sval64[2] = int64(x32) //ppc64:-"MOVBZ\tR\\d+,\\sR\\d+" - //ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" - val64[0] = uint64(u8) + //ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" + val64[0] = uint64(u8) // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" - val64[1] = uint64(u16) + // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" + val64[1] = uint64(u16) // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+" // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+" @@ -121,15 +121,15 @@ func setnox(x8 int8, u8 uint8, y8 int8, z8 uint8, x16 int16, u16 uint16, x32 int func cmp16(x8 int8, u8 uint8, x32 int32, u32 uint32, x64 int64, u64 uint64) bool { // ppc64:-"MOVB\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" + // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" if int16(x8) == sval16[0] { return true } // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" - if uint16(u8) == val16[0] { - return true + // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" + if uint16(u8) == val16[0] { + return true } // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+" @@ -174,16 +174,16 @@ func cmp16(x8 int8, u8 uint8, x32 int32, u32 uint32, x64 int64, u64 uint64) bool func cmp32(x8 int8, u8 uint8, x16 int16, u16 uint16, x64 int64, u64 uint64) bool { // ppc64:-"MOVB\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" - if int32(x8) == sval32[0] { - return true - } + // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" + if int32(x8) == sval32[0] { + return true + } // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" - if uint32(u8) == val32[0] { - return true - } + // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" + if uint32(u8) == val32[0] { + return true + } // ppc64:-"MOVH\tR\\d+,\\sR\\d+" // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" @@ -213,43 +213,41 @@ func cmp32(x8 int8, u8 uint8, x16 int16, u16 uint16, x64 int64, u64 uint64) bool return false } - -func cmp64(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) bool { +func cmp64(x8 int8, u8 uint8, x16 int16, u16 uint16, x32 int32, u32 uint32) bool { // ppc64:-"MOVB\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" - if int64(x8) == sval64[0] { - return true - } + // ppc64le:-"MOVB\tR\\d+,\\sR\\d+" + if int64(x8) == sval64[0] { + return true + } // ppc64:-"MOVBZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" - if uint64(u8) == val64[0] { - return true - } + // ppc64le:-"MOVBZ\tR\\d+,\\sR\\d+" + if uint64(u8) == val64[0] { + return true + } // ppc64:-"MOVH\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" - if int64(x16) == sval64[0] { - return true - } + // ppc64le:-"MOVH\tR\\d+,\\sR\\d+" + if int64(x16) == sval64[0] { + return true + } // ppc64:-"MOVHZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" - if uint64(u16) == val64[0] { - return true - } + // ppc64le:-"MOVHZ\tR\\d+,\\sR\\d+" + if uint64(u16) == val64[0] { + return true + } // ppc64:-"MOVW\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVW\tR\\d+,\\sR\\d+" - if int64(x32) == sval64[0] { - return true - } + // ppc64le:-"MOVW\tR\\d+,\\sR\\d+" + if int64(x32) == sval64[0] { + return true + } // ppc64:-"MOVWZ\tR\\d+,\\sR\\d+" - // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+" - if uint64(u32) == val64[0] { - return true - } - return false + // ppc64le:-"MOVWZ\tR\\d+,\\sR\\d+" + if uint64(u32) == val64[0] { + return true + } + return false } - diff --git a/test/codegen/race.go b/test/codegen/race.go new file mode 100644 index 00000000..ed6706f8 --- /dev/null +++ b/test/codegen/race.go @@ -0,0 +1,20 @@ +// asmcheck -race + +// Copyright 2019 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. + +package codegen + +// Check that we elide racefuncenter/racefuncexit for +// functions with no calls (but which might panic +// in various ways). See issue 31219. +// amd64:-"CALL.*racefuncenter.*" +func RaceMightPanic(a []int, i, j, k, s int) { + var b [4]int + _ = b[i] // panicIndex + _ = a[i:j] // panicSlice + _ = a[i:j:k] // also panicSlice + _ = i << s // panicShift + _ = i / j // panicDivide +} diff --git a/test/codegen/shift.go b/test/codegen/shift.go index 93fa8288..4ae9d7d6 100644 --- a/test/codegen/shift.go +++ b/test/codegen/shift.go @@ -12,47 +12,47 @@ package codegen func lshMask64x64(v int64, s uint64) int64 { // s390x:-".*AND",-".*MOVDGE" - return v << (s&63) + return v << (s & 63) } func rshMask64Ux64(v uint64, s uint64) uint64 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func rshMask64x64(v int64, s uint64) int64 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func lshMask32x64(v int32, s uint64) int32 { // s390x:-".*AND",-".*MOVDGE" - return v << (s&63) + return v << (s & 63) } func rshMask32Ux64(v uint32, s uint64) uint32 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func rshMask32x64(v int32, s uint64) int32 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func lshMask64x32(v int64, s uint32) int64 { // s390x:-".*AND",-".*MOVDGE" - return v << (s&63) + return v << (s & 63) } func rshMask64Ux32(v uint64, s uint32) uint64 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func rshMask64x32(v int64, s uint32) int64 { // s390x:-".*AND",-".*MOVDGE" - return v >> (s&63) + return v >> (s & 63) } func lshMask64x32Ext(v int64, s int32) int64 { @@ -70,6 +70,34 @@ func rshMask64x32Ext(v int64, s int32) int64 { return v >> uint(s&63) } +// --------------- // +// signed shifts // +// --------------- // + +// We do want to generate a test + panicshift for these cases. +func lshSigned(v8 int8, v16 int16, v32 int32, v64 int64, x int) { + // amd64:"TESTB" + _ = x << v8 + // amd64:"TESTW" + _ = x << v16 + // amd64:"TESTL" + _ = x << v32 + // amd64:"TESTQ" + _ = x << v64 +} + +// We want to avoid generating a test + panicshift for these cases. +func lshSignedMasked(v8 int8, v16 int16, v32 int32, v64 int64, x int) { + // amd64:-"TESTB" + _ = x << (v8 & 7) + // amd64:-"TESTW" + _ = x << (v16 & 15) + // amd64:-"TESTL" + _ = x << (v32 & 31) + // amd64:-"TESTQ" + _ = x << (v64 & 63) +} + // ------------------ // // bounded shifts // // ------------------ // diff --git a/test/codegen/slices.go b/test/codegen/slices.go index 15dbcee7..6477c6f6 100644 --- a/test/codegen/slices.go +++ b/test/codegen/slices.go @@ -61,3 +61,13 @@ func SliceExtensionInt64(s []int, l64 int64) []int { // 386:-`.*runtime\.memclr` return append(s, make([]int, l64)...) } + +// ---------------------- // +// Nil check of &s[0] // +// ---------------------- // +// See issue 30366 +func SliceNilCheck(s []int) { + p := &s[0] + // amd64:-`TESTB` + _ = *p +} diff --git a/test/codegen/stack.go b/test/codegen/stack.go index ed2c1ed9..37d378aa 100644 --- a/test/codegen/stack.go +++ b/test/codegen/stack.go @@ -98,3 +98,19 @@ func check_asmout(a, b int) int { // arm:`.*b\+4\(FP\)` return b } + +// Check that simple functions get promoted to nosplit, even when +// they might panic in various ways. See issue 31219. +// amd64:"TEXT\t.*NOSPLIT.*" +func MightPanic(a []int, i, j, k, s int) { + _ = a[i] // panicIndex + _ = a[i:j] // panicSlice + _ = a[i:j:k] // also panicSlice + _ = i << s // panicShift + _ = i / j // panicDivide +} + +func Defer() { + // amd64:`CALL\truntime\.deferprocStack` + defer func() {}() +} diff --git a/test/const1.go b/test/const1.go index 62abe414..3fd5b555 100644 --- a/test/const1.go +++ b/test/const1.go @@ -68,7 +68,7 @@ var ( c3 float64 = float64(Big) * Big // ERROR "overflow" c4 = Big * Big // ERROR "overflow" c5 = Big / 0 // ERROR "division by zero" - c6 = 1000 % 1e3 // ERROR "floating-point % operation|expected integer type" + c6 = 1000 % 1e3 // ERROR "invalid operation|expected integer type" ) func f(int) diff --git a/test/copy1.go b/test/copy1.go index 14285498..e1fa1055 100644 --- a/test/copy1.go +++ b/test/copy1.go @@ -14,7 +14,7 @@ func main() { si := make([]int, 8) sf := make([]float64, 8) - _ = copy() // ERROR "missing arguments" + _ = copy() // ERROR "not enough arguments" _ = copy(1, 2, 3) // ERROR "too many arguments" _ = copy(si, "hi") // ERROR "have different element types.*int.*string" diff --git a/test/escape2.go b/test/escape2.go index a39291e8..f682621c 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -19,7 +19,7 @@ import ( var gxx *int func foo1(x int) { // ERROR "moved to heap: x$" - gxx = &x // ERROR "&x escapes to heap$" + gxx = &x } func foo2(yy *int) { // ERROR "leaking param: yy$" @@ -27,7 +27,7 @@ func foo2(yy *int) { // ERROR "leaking param: yy$" } func foo3(x int) *int { // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } type T *T @@ -43,7 +43,7 @@ func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not e // xx isn't going anywhere, so taking address of yy is ok func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" - xx = &yy // ERROR "foo5 &yy does not escape$" + xx = &yy } func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" @@ -70,8 +70,8 @@ func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does no func foo11() int { x, y := 0, 42 - xx := &x // ERROR "foo11 &x does not escape$" - yy := &y // ERROR "foo11 &y does not escape$" + xx := &x + yy := &y *xx = *yy return x } @@ -93,7 +93,7 @@ func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" } func foo15(yy *int) { // ERROR "moved to heap: yy$" - xxx = &yy // ERROR "&yy escapes to heap$" + xxx = &yy } func foo16(yy *int) { // ERROR "leaking param: yy$" @@ -105,7 +105,7 @@ func foo17(yy *int) { // ERROR "foo17 yy does not escape$" } func foo18(y int) { // ERROR "moved to heap: y$" - *xxx = &y // ERROR "&y escapes to heap$" + *xxx = &y } func foo19(y int) { @@ -121,7 +121,7 @@ func NewBar() *Bar { return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" } -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" +func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } @@ -134,7 +134,7 @@ func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" } func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return &b.i // ERROR "&b.i escapes to heap$" + return &b.i } func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" @@ -147,19 +147,19 @@ func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$ func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" v := 0 // ERROR "moved to heap: v$" - b.ii = &v // ERROR "&v escapes to heap$" + b.ii = &v return b.ii } func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" v := 0 // ERROR "moved to heap: v$" - b.ii = &v // ERROR "&v escapes to heap$" + b.ii = &v return b.ii } func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" v := 0 - b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$" + b.ii = &v return b.i } @@ -181,7 +181,7 @@ func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" } func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.i[:] // ERROR "b.i escapes to heap$" + return b.i[:] } func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" @@ -193,12 +193,12 @@ func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not esca } func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" - b.ii = b.i[0:4] // ERROR "b.i escapes to heap$" + b.ii = b.i[0:4] } func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" var buf []int - buf = b.i[0:] // ERROR "b.i escapes to heap$" + buf = b.i[0:] b.ii = buf } @@ -212,7 +212,7 @@ func foo21() func() int { func foo21a() func() int { x := 42 // ERROR "moved to heap: x$" return func() int { // ERROR "func literal escapes to heap$" - x++ // ERROR "&x escapes to heap$" + x++ return x } } @@ -239,12 +239,12 @@ func foo23a(x int) func() int { func foo23b(x int) *(func() int) { f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" - return &f // ERROR "&f escapes to heap$" + return &f } func foo23c(x int) func() int { // ERROR "moved to heap: x$" return func() int { // ERROR "func literal escapes to heap$" - x++ // ERROR "&x escapes to heap$" + x++ return x } } @@ -267,11 +267,11 @@ func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" } func foo31(x int) int { // ERROR "moved to heap: x$" - return fooleak(&x) // ERROR "&x escapes to heap$" + return fooleak(&x) } func foo32(x int) int { - return foonoleak(&x) // ERROR "foo32 &x does not escape$" + return foonoleak(&x) } type Foo struct { @@ -299,15 +299,15 @@ func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" } func foo41(x int) { // ERROR "moved to heap: x$" - F.xx = &x // ERROR "&x escapes to heap$" + F.xx = &x } func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" - f.xx = &x // ERROR "&x escapes to heap$" + f.xx = &x } func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" - f.xx = &x // ERROR "&x escapes to heap$" + f.xx = &x } func foo44(yy *int) { // ERROR "leaking param: yy$" @@ -324,7 +324,7 @@ func (f *Foo) foo46() { // ERROR "leaking param content: f$" } func (f *Foo) foo47() { // ERROR "leaking param: f$" - f.xx = &f.x // ERROR "&f.x escapes to heap$" + f.xx = &f.x } var ptrSlice []*int @@ -340,38 +340,38 @@ func foo51(i *int) { // ERROR "leaking param: i$" } func indaddr1(x int) *int { // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *&x // ERROR "indaddr2 &x does not escape$" + return *&x } func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$" + return *(**int)(unsafe.Pointer(&x)) } // From package math: func Float32bits(f float32) uint32 { - return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$" + return *(*uint32)(unsafe.Pointer(&f)) } func Float32frombits(b uint32) float32 { - return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$" + return *(*float32)(unsafe.Pointer(&b)) } func Float64bits(f float64) uint64 { - return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$" + return *(*uint64)(unsafe.Pointer(&f)) } func Float64frombits(b uint64) float64 { - return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$" + return *(*float64)(unsafe.Pointer(&b)) } // contrast with func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" - return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$" + return (*uint64)(unsafe.Pointer(&f)) } func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" @@ -384,7 +384,7 @@ func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level return val case *int8: v := int(*val) // ERROR "moved to heap: v$" - return &v // ERROR "&v escapes to heap$" + return &v } return nil } @@ -501,20 +501,20 @@ func foo71(x *int) []*int { // ERROR "leaking param: x$" func foo71a(x int) []*int { // ERROR "moved to heap: x$" var y []*int - y = append(y, &x) // ERROR "&x escapes to heap$" + y = append(y, &x) return y } func foo72() { var x int var y [1]*int - y[0] = &x // ERROR "foo72 &x does not escape$" + y[0] = &x } func foo72aa() [10]*int { var x int // ERROR "moved to heap: x$" var y [10]*int - y[0] = &x // ERROR "&x escapes to heap$" + y[0] = &x return y } @@ -523,7 +523,7 @@ func foo72a() { for i := 0; i < 10; i++ { // escapes its scope x := i // ERROR "moved to heap: x$" - y[i] = &x // ERROR "&x escapes to heap$" + y[i] = &x } return } @@ -532,7 +532,7 @@ func foo72b() [10]*int { var y [10]*int for i := 0; i < 10; i++ { x := i // ERROR "moved to heap: x$" - y[i] = &x // ERROR "&x escapes to heap$" + y[i] = &x } return y } @@ -555,7 +555,7 @@ func foo731() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope defer func() { // ERROR "func literal escapes to heap$" - vv = 42 // ERROR "&vv escapes to heap$" + vv = 42 println(vv) }() } @@ -579,7 +579,7 @@ func foo74a() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope fn := func() { // ERROR "func literal escapes to heap$" - vv += 1 // ERROR "&vv escapes to heap$" + vv += 1 println(vv) } defer fn() @@ -606,7 +606,7 @@ func foo74c() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope array[i] = func() { // ERROR "func literal escapes to heap$" - println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$" + println(&vv) } } } @@ -616,7 +616,7 @@ func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to resu } func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" - return &x[0] // ERROR "&x\[0\] escapes to heap$" + return &x[0] } func foo75(z *int) { // ERROR "foo75 z does not escape$" @@ -703,12 +703,12 @@ func dotdotdot() { } func foo78(z int) *int { // ERROR "moved to heap: z$" - return &z // ERROR "&z escapes to heap$" + return &z } func foo78a(z int) *int { // ERROR "moved to heap: z$" - y := &z // ERROR "&z escapes to heap$" - x := &y // ERROR "foo78a &y does not escape$" + y := &z + x := &y return *x // really return y } @@ -740,12 +740,12 @@ func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not esca func foo82() { var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" - go noop(tee(&z)) // ERROR "&z escapes to heap$" - go noop(&x, &y) // ERROR "&x escapes to heap$" "&y escapes to heap$" + go noop(tee(&z)) + go noop(&x, &y) for { var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" - defer noop(tee(&u)) // ERROR "&u escapes to heap$" - defer noop(&v, &w) // ERROR "&v escapes to heap$" "&w escapes to heap$" + defer noop(tee(&u)) + defer noop(&v, &w) } } @@ -758,7 +758,7 @@ type LimitedFooer struct { N int64 } -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" } @@ -837,7 +837,7 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" // does not leak m func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" for i := range m { // ERROR "moved to heap: i$" - return &i // ERROR "&i escapes to heap$" + return &i } return nil } @@ -917,10 +917,10 @@ func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" func foo116(b bool) *int { if b { x := 1 // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } else { y := 1 // ERROR "moved to heap: y$" - return &y // ERROR "&y escapes to heap$" + return &y } return nil } @@ -932,7 +932,7 @@ func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escap func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" + unknown(&x) } func external(*int) @@ -1184,17 +1184,17 @@ L1: func foo124(x **int) { // ERROR "foo124 x does not escape$" var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo124 func literal does not escape$" - *x = p // ERROR "leaking closure reference p$" + *x = p }() } func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo125 func literal does not escape$" - ch <- p // ERROR "leaking closure reference p$" + ch <- p }() } @@ -1204,7 +1204,7 @@ func foo126() { // loopdepth 1 var i int // ERROR "moved to heap: i$" func() { // ERROR "foo126 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i" + px = &i }() } _ = px @@ -1214,25 +1214,25 @@ var px *int func foo127() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i q := p px = q } func foo128() { var i int - p := &i // ERROR "foo128 &i does not escape$" + p := &i q := p _ = q } func foo129() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo129 func literal does not escape$" - q := p // ERROR "leaking closure reference p$" + q := p func() { // ERROR "foo129.func1 func literal does not escape$" - r := q // ERROR "leaking closure reference q$" + r := q px = r }() }() @@ -1242,7 +1242,7 @@ func foo130() { for { var i int // ERROR "moved to heap: i$" func() { // ERROR "foo130 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } } @@ -1250,27 +1250,27 @@ func foo130() { func foo131() { var i int // ERROR "moved to heap: i$" func() { // ERROR "foo131 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo132() { var i int // ERROR "moved to heap: i$" go func() { // ERROR "func literal escapes to heap$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo133() { var i int // ERROR "moved to heap: i$" defer func() { // ERROR "foo133 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo134() { var i int - p := &i // ERROR "foo134 &i does not escape$" + p := &i func() { // ERROR "foo134 func literal does not escape$" q := p func() { // ERROR "foo134.func1 func literal does not escape$" @@ -1282,7 +1282,7 @@ func foo134() { func foo135() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i go func() { // ERROR "func literal escapes to heap$" q := p func() { // ERROR "foo135.func1 func literal does not escape$" @@ -1294,11 +1294,11 @@ func foo135() { func foo136() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i go func() { // ERROR "func literal escapes to heap$" - q := p // ERROR "leaking closure reference p$" + q := p func() { // ERROR "foo136.func1 func literal does not escape$" - r := q // ERROR "leaking closure reference q$" + r := q px = r }() }() @@ -1306,9 +1306,9 @@ func foo136() { func foo137() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo137 func literal does not escape$" - q := p // ERROR "leaking closure reference p$" + q := p go func() { // ERROR "func literal escapes to heap$" r := q _ = r @@ -1321,7 +1321,7 @@ func foo138() *byte { x [1]byte } t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$" + return &t.x[0] } func foo139() *byte { @@ -1331,7 +1331,7 @@ func foo139() *byte { } } t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x.y // ERROR "&t.x.y escapes to heap$" + return &t.x.y } // issue 4751 @@ -1360,20 +1360,20 @@ func F2([]byte) func F3(x []byte) // ERROR "F3 x does not escape$" -func F4(x []byte) +func F4(x []byte) // ERROR "leaking param: x$" func G() { var buf1 [10]byte - F1(buf1[:]) // ERROR "G buf1 does not escape$" + F1(buf1[:]) var buf2 [10]byte // ERROR "moved to heap: buf2$" - F2(buf2[:]) // ERROR "buf2 escapes to heap$" + F2(buf2[:]) var buf3 [10]byte - F3(buf3[:]) // ERROR "G buf3 does not escape$" + F3(buf3[:]) var buf4 [10]byte // ERROR "moved to heap: buf4$" - F4(buf4[:]) // ERROR "buf4 escapes to heap$" + F4(buf4[:]) } type Tm struct { @@ -1404,7 +1404,7 @@ func foo143() { func() { // ERROR "foo143 func literal does not escape$" for i := 0; i < 1; i++ { var t Tm - t.M() // ERROR "foo143.func1 t does not escape$" + t.M() } }() } @@ -1420,9 +1420,9 @@ func foo144a(*int) func foo144() { var x int - foo144a(&x) // ERROR "foo144 &x does not escape$" + foo144a(&x) var y int - foo144b(&y) // ERROR "foo144 &y does not escape$" + foo144b(&y) } //go:noescape @@ -1437,27 +1437,27 @@ type List struct { func foo145(l List) { // ERROR "foo145 l does not escape$" var p *List - for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$" + for p = &l; p.Next != nil; p = p.Next { } } func foo146(l List) { // ERROR "foo146 l does not escape$" var p *List - p = &l // ERROR "foo146 &l does not escape$" + p = &l for ; p.Next != nil; p = p.Next { } } func foo147(l List) { // ERROR "foo147 l does not escape$" var p *List - p = &l // ERROR "foo147 &l does not escape$" + p = &l for p.Next != nil { p = p.Next } } func foo148(l List) { // ERROR "foo148 l does not escape$" - for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$" + for p := &l; p.Next != nil; p = p.Next { } } @@ -1466,7 +1466,7 @@ func foo148(l List) { // ERROR "foo148 l does not escape$" func foo149(l List) { // ERROR "foo149 l does not escape$" var p *List for { - for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$" + for p = &l; p.Next != nil; p = p.Next { } } } @@ -1494,25 +1494,25 @@ func foo151(x *int) { // ERROR "leaking param: x$" func bar151() { var a [64]int // ERROR "moved to heap: a$" a[4] = 101 - foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$" + foo151(&(&a)[4:8][0]) } func bar151b() { var a [10]int // ERROR "moved to heap: a$" - b := a[:] // ERROR "a escapes to heap$" - foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$" + b := a[:] + foo151(&b[4:8][0]) } func bar151c() { var a [64]int // ERROR "moved to heap: a$" a[4] = 101 - foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$" + foo151(&(&a)[4:8:8][0]) } func bar151d() { var a [10]int // ERROR "moved to heap: a$" - b := a[:] // ERROR "a escapes to heap$" - foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$" + b := a[:] + foo151(&b[4:8:8][0]) } // issue 8120 @@ -1529,24 +1529,23 @@ type V struct { s *string } -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" - return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape" +func NewV(u U) *V { // ERROR "leaking param: u$" + return &V{u.String()} // ERROR "&V literal escapes to heap$" } func foo152() { a := "a" // ERROR "moved to heap: a$" - u := U{&a} // ERROR "&a escapes to heap$" + u := U{&a} v := NewV(u) println(v) } // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" +func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } panic(0) } @@ -1554,7 +1553,7 @@ func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level // issue 8185 - &result escaping into result func f() (x int, y *int) { // ERROR "moved to heap: x$" - y = &x // ERROR "&x escapes to heap$" + y = &x return } @@ -1572,21 +1571,21 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$" + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" 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$" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" sink = x // ERROR "x escapes to heap$" } @@ -1609,7 +1608,7 @@ func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" } func (b *Buffer) bar() { // ERROR "leaking param: b$" - b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$" + b.buf1 = b.arr[1:2] } func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" @@ -1644,7 +1643,7 @@ type StructWithString struct { func fieldFlowTracking() { var x StructWithString i := 0 // ERROR "moved to heap: i$" - x.p = &i // ERROR "&i escapes to heap$" + x.p = &i sink = x.s // ERROR "x.s escapes to heap$" } @@ -1806,7 +1805,7 @@ func issue10353() { issue10353a(x)() } -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" +func issue10353a(x *int) func() { // ERROR "leaking param: x$" return func() { // ERROR "func literal escapes to heap$" println(*x) } @@ -1836,11 +1835,11 @@ func issue12397(x, y int) { // ERROR "moved to heap: y$" if false { gxx = &x } else { - gxx = &y // ERROR "&y escapes to heap$" + gxx = &y } if true { - gxx = &y // ERROR "&y escapes to heap$" + gxx = &y } else { gxx = &x } diff --git a/test/escape2n.go b/test/escape2n.go index 989cf18d..2fd26f7c 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l +// errorcheck -0 -N -m -l -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -19,7 +19,7 @@ import ( var gxx *int func foo1(x int) { // ERROR "moved to heap: x$" - gxx = &x // ERROR "&x escapes to heap$" + gxx = &x } func foo2(yy *int) { // ERROR "leaking param: yy$" @@ -27,7 +27,7 @@ func foo2(yy *int) { // ERROR "leaking param: yy$" } func foo3(x int) *int { // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } type T *T @@ -43,7 +43,7 @@ func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not e // xx isn't going anywhere, so taking address of yy is ok func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" - xx = &yy // ERROR "foo5 &yy does not escape$" + xx = &yy } func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" @@ -70,8 +70,8 @@ func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does no func foo11() int { x, y := 0, 42 - xx := &x // ERROR "foo11 &x does not escape$" - yy := &y // ERROR "foo11 &y does not escape$" + xx := &x + yy := &y *xx = *yy return x } @@ -93,7 +93,7 @@ func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" } func foo15(yy *int) { // ERROR "moved to heap: yy$" - xxx = &yy // ERROR "&yy escapes to heap$" + xxx = &yy } func foo16(yy *int) { // ERROR "leaking param: yy$" @@ -105,7 +105,7 @@ func foo17(yy *int) { // ERROR "foo17 yy does not escape$" } func foo18(y int) { // ERROR "moved to heap: y$" - *xxx = &y // ERROR "&y escapes to heap$" + *xxx = &y } func foo19(y int) { @@ -121,7 +121,7 @@ func NewBar() *Bar { return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" } -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" +func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } @@ -134,7 +134,7 @@ func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" } func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return &b.i // ERROR "&b.i escapes to heap$" + return &b.i } func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" @@ -147,19 +147,19 @@ func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$ func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" v := 0 // ERROR "moved to heap: v$" - b.ii = &v // ERROR "&v escapes to heap$" + b.ii = &v return b.ii } func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" v := 0 // ERROR "moved to heap: v$" - b.ii = &v // ERROR "&v escapes to heap$" + b.ii = &v return b.ii } func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" v := 0 - b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$" + b.ii = &v return b.i } @@ -181,7 +181,7 @@ func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" } func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.i[:] // ERROR "b.i escapes to heap$" + return b.i[:] } func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" @@ -193,12 +193,12 @@ func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not esca } func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" - b.ii = b.i[0:4] // ERROR "b.i escapes to heap$" + b.ii = b.i[0:4] } func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" var buf []int - buf = b.i[0:] // ERROR "b.i escapes to heap$" + buf = b.i[0:] b.ii = buf } @@ -212,7 +212,7 @@ func foo21() func() int { func foo21a() func() int { x := 42 // ERROR "moved to heap: x$" return func() int { // ERROR "func literal escapes to heap$" - x++ // ERROR "&x escapes to heap$" + x++ return x } } @@ -239,12 +239,12 @@ func foo23a(x int) func() int { func foo23b(x int) *(func() int) { f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" - return &f // ERROR "&f escapes to heap$" + return &f } func foo23c(x int) func() int { // ERROR "moved to heap: x$" return func() int { // ERROR "func literal escapes to heap$" - x++ // ERROR "&x escapes to heap$" + x++ return x } } @@ -267,11 +267,11 @@ func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" } func foo31(x int) int { // ERROR "moved to heap: x$" - return fooleak(&x) // ERROR "&x escapes to heap$" + return fooleak(&x) } func foo32(x int) int { - return foonoleak(&x) // ERROR "foo32 &x does not escape$" + return foonoleak(&x) } type Foo struct { @@ -299,15 +299,15 @@ func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" } func foo41(x int) { // ERROR "moved to heap: x$" - F.xx = &x // ERROR "&x escapes to heap$" + F.xx = &x } func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" - f.xx = &x // ERROR "&x escapes to heap$" + f.xx = &x } func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" - f.xx = &x // ERROR "&x escapes to heap$" + f.xx = &x } func foo44(yy *int) { // ERROR "leaking param: yy$" @@ -324,7 +324,7 @@ func (f *Foo) foo46() { // ERROR "leaking param content: f$" } func (f *Foo) foo47() { // ERROR "leaking param: f$" - f.xx = &f.x // ERROR "&f.x escapes to heap$" + f.xx = &f.x } var ptrSlice []*int @@ -340,38 +340,38 @@ func foo51(i *int) { // ERROR "leaking param: i$" } func indaddr1(x int) *int { // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *&x // ERROR "indaddr2 &x does not escape$" + return *&x } func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$" + return *(**int)(unsafe.Pointer(&x)) } // From package math: func Float32bits(f float32) uint32 { - return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$" + return *(*uint32)(unsafe.Pointer(&f)) } func Float32frombits(b uint32) float32 { - return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$" + return *(*float32)(unsafe.Pointer(&b)) } func Float64bits(f float64) uint64 { - return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$" + return *(*uint64)(unsafe.Pointer(&f)) } func Float64frombits(b uint64) float64 { - return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$" + return *(*float64)(unsafe.Pointer(&b)) } // contrast with func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" - return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$" + return (*uint64)(unsafe.Pointer(&f)) } func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" @@ -384,7 +384,7 @@ func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level return val case *int8: v := int(*val) // ERROR "moved to heap: v$" - return &v // ERROR "&v escapes to heap$" + return &v } return nil } @@ -501,20 +501,20 @@ func foo71(x *int) []*int { // ERROR "leaking param: x$" func foo71a(x int) []*int { // ERROR "moved to heap: x$" var y []*int - y = append(y, &x) // ERROR "&x escapes to heap$" + y = append(y, &x) return y } func foo72() { var x int var y [1]*int - y[0] = &x // ERROR "foo72 &x does not escape$" + y[0] = &x } func foo72aa() [10]*int { var x int // ERROR "moved to heap: x$" var y [10]*int - y[0] = &x // ERROR "&x escapes to heap$" + y[0] = &x return y } @@ -523,7 +523,7 @@ func foo72a() { for i := 0; i < 10; i++ { // escapes its scope x := i // ERROR "moved to heap: x$" - y[i] = &x // ERROR "&x escapes to heap$" + y[i] = &x } return } @@ -532,7 +532,7 @@ func foo72b() [10]*int { var y [10]*int for i := 0; i < 10; i++ { x := i // ERROR "moved to heap: x$" - y[i] = &x // ERROR "&x escapes to heap$" + y[i] = &x } return y } @@ -555,7 +555,7 @@ func foo731() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope defer func() { // ERROR "func literal escapes to heap$" - vv = 42 // ERROR "&vv escapes to heap$" + vv = 42 println(vv) }() } @@ -579,7 +579,7 @@ func foo74a() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope fn := func() { // ERROR "func literal escapes to heap$" - vv += 1 // ERROR "&vv escapes to heap$" + vv += 1 println(vv) } defer fn() @@ -606,7 +606,7 @@ func foo74c() { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope array[i] = func() { // ERROR "func literal escapes to heap$" - println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$" + println(&vv) } } } @@ -616,7 +616,7 @@ func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to resu } func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" - return &x[0] // ERROR "&x\[0\] escapes to heap$" + return &x[0] } func foo75(z *int) { // ERROR "foo75 z does not escape$" @@ -703,12 +703,12 @@ func dotdotdot() { } func foo78(z int) *int { // ERROR "moved to heap: z$" - return &z // ERROR "&z escapes to heap$" + return &z } func foo78a(z int) *int { // ERROR "moved to heap: z$" - y := &z // ERROR "&z escapes to heap$" - x := &y // ERROR "foo78a &y does not escape$" + y := &z + x := &y return *x // really return y } @@ -740,12 +740,12 @@ func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not esca func foo82() { var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" - go noop(tee(&z)) // ERROR "&z escapes to heap$" - go noop(&x, &y) // ERROR "&x escapes to heap$" "&y escapes to heap$" + go noop(tee(&z)) + go noop(&x, &y) for { var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" - defer noop(tee(&u)) // ERROR "&u escapes to heap$" - defer noop(&v, &w) // ERROR "&v escapes to heap$" "&w escapes to heap$" + defer noop(tee(&u)) + defer noop(&v, &w) } } @@ -758,7 +758,7 @@ type LimitedFooer struct { N int64 } -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" } @@ -837,7 +837,7 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" // does not leak m func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" for i := range m { // ERROR "moved to heap: i$" - return &i // ERROR "&i escapes to heap$" + return &i } return nil } @@ -917,10 +917,10 @@ func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" func foo116(b bool) *int { if b { x := 1 // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } else { y := 1 // ERROR "moved to heap: y$" - return &y // ERROR "&y escapes to heap$" + return &y } return nil } @@ -932,7 +932,7 @@ func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escap func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" + unknown(&x) } func external(*int) @@ -1184,17 +1184,17 @@ L1: func foo124(x **int) { // ERROR "foo124 x does not escape$" var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo124 func literal does not escape$" - *x = p // ERROR "leaking closure reference p$" + *x = p }() } func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo125 func literal does not escape$" - ch <- p // ERROR "leaking closure reference p$" + ch <- p }() } @@ -1204,7 +1204,7 @@ func foo126() { // loopdepth 1 var i int // ERROR "moved to heap: i$" func() { // ERROR "foo126 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i" + px = &i }() } _ = px @@ -1214,25 +1214,25 @@ var px *int func foo127() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i q := p px = q } func foo128() { var i int - p := &i // ERROR "foo128 &i does not escape$" + p := &i q := p _ = q } func foo129() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo129 func literal does not escape$" - q := p // ERROR "leaking closure reference p$" + q := p func() { // ERROR "foo129.func1 func literal does not escape$" - r := q // ERROR "leaking closure reference q$" + r := q px = r }() }() @@ -1242,7 +1242,7 @@ func foo130() { for { var i int // ERROR "moved to heap: i$" func() { // ERROR "foo130 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } } @@ -1250,27 +1250,27 @@ func foo130() { func foo131() { var i int // ERROR "moved to heap: i$" func() { // ERROR "foo131 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo132() { var i int // ERROR "moved to heap: i$" go func() { // ERROR "func literal escapes to heap$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo133() { var i int // ERROR "moved to heap: i$" defer func() { // ERROR "foo133 func literal does not escape$" - px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$" + px = &i }() } func foo134() { var i int - p := &i // ERROR "foo134 &i does not escape$" + p := &i func() { // ERROR "foo134 func literal does not escape$" q := p func() { // ERROR "foo134.func1 func literal does not escape$" @@ -1282,7 +1282,7 @@ func foo134() { func foo135() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i go func() { // ERROR "func literal escapes to heap$" q := p func() { // ERROR "foo135.func1 func literal does not escape$" @@ -1294,11 +1294,11 @@ func foo135() { func foo136() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i go func() { // ERROR "func literal escapes to heap$" - q := p // ERROR "leaking closure reference p$" + q := p func() { // ERROR "foo136.func1 func literal does not escape$" - r := q // ERROR "leaking closure reference q$" + r := q px = r }() }() @@ -1306,9 +1306,9 @@ func foo136() { func foo137() { var i int // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" + p := &i func() { // ERROR "foo137 func literal does not escape$" - q := p // ERROR "leaking closure reference p$" + q := p go func() { // ERROR "func literal escapes to heap$" r := q _ = r @@ -1321,7 +1321,7 @@ func foo138() *byte { x [1]byte } t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$" + return &t.x[0] } func foo139() *byte { @@ -1331,7 +1331,7 @@ func foo139() *byte { } } t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x.y // ERROR "&t.x.y escapes to heap$" + return &t.x.y } // issue 4751 @@ -1360,20 +1360,20 @@ func F2([]byte) func F3(x []byte) // ERROR "F3 x does not escape$" -func F4(x []byte) +func F4(x []byte) // ERROR "leaking param: x$" func G() { var buf1 [10]byte - F1(buf1[:]) // ERROR "G buf1 does not escape$" + F1(buf1[:]) var buf2 [10]byte // ERROR "moved to heap: buf2$" - F2(buf2[:]) // ERROR "buf2 escapes to heap$" + F2(buf2[:]) var buf3 [10]byte - F3(buf3[:]) // ERROR "G buf3 does not escape$" + F3(buf3[:]) var buf4 [10]byte // ERROR "moved to heap: buf4$" - F4(buf4[:]) // ERROR "buf4 escapes to heap$" + F4(buf4[:]) } type Tm struct { @@ -1404,7 +1404,7 @@ func foo143() { func() { // ERROR "foo143 func literal does not escape$" for i := 0; i < 1; i++ { var t Tm - t.M() // ERROR "foo143.func1 t does not escape$" + t.M() } }() } @@ -1420,9 +1420,9 @@ func foo144a(*int) func foo144() { var x int - foo144a(&x) // ERROR "foo144 &x does not escape$" + foo144a(&x) var y int - foo144b(&y) // ERROR "foo144 &y does not escape$" + foo144b(&y) } //go:noescape @@ -1437,27 +1437,27 @@ type List struct { func foo145(l List) { // ERROR "foo145 l does not escape$" var p *List - for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$" + for p = &l; p.Next != nil; p = p.Next { } } func foo146(l List) { // ERROR "foo146 l does not escape$" var p *List - p = &l // ERROR "foo146 &l does not escape$" + p = &l for ; p.Next != nil; p = p.Next { } } func foo147(l List) { // ERROR "foo147 l does not escape$" var p *List - p = &l // ERROR "foo147 &l does not escape$" + p = &l for p.Next != nil { p = p.Next } } func foo148(l List) { // ERROR "foo148 l does not escape$" - for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$" + for p := &l; p.Next != nil; p = p.Next { } } @@ -1466,7 +1466,7 @@ func foo148(l List) { // ERROR "foo148 l does not escape$" func foo149(l List) { // ERROR "foo149 l does not escape$" var p *List for { - for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$" + for p = &l; p.Next != nil; p = p.Next { } } } @@ -1494,25 +1494,25 @@ func foo151(x *int) { // ERROR "leaking param: x$" func bar151() { var a [64]int // ERROR "moved to heap: a$" a[4] = 101 - foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$" + foo151(&(&a)[4:8][0]) } func bar151b() { var a [10]int // ERROR "moved to heap: a$" - b := a[:] // ERROR "a escapes to heap$" - foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$" + b := a[:] + foo151(&b[4:8][0]) } func bar151c() { var a [64]int // ERROR "moved to heap: a$" a[4] = 101 - foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$" + foo151(&(&a)[4:8:8][0]) } func bar151d() { var a [10]int // ERROR "moved to heap: a$" - b := a[:] // ERROR "a escapes to heap$" - foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$" + b := a[:] + foo151(&b[4:8:8][0]) } // issue 8120 @@ -1529,24 +1529,23 @@ type V struct { s *string } -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" - return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape" +func NewV(u U) *V { // ERROR "leaking param: u$" + return &V{u.String()} // ERROR "&V literal escapes to heap$" } func foo152() { a := "a" // ERROR "moved to heap: a$" - u := U{&a} // ERROR "&a escapes to heap$" + u := U{&a} v := NewV(u) println(v) } // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" +func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" - return &x // ERROR "&x escapes to heap$" + return &x } panic(0) } @@ -1554,7 +1553,7 @@ func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level // issue 8185 - &result escaping into result func f() (x int, y *int) { // ERROR "moved to heap: x$" - y = &x // ERROR "&x escapes to heap$" + y = &x return } @@ -1572,21 +1571,21 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$" + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" 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$" + x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" sink = x // ERROR "x escapes to heap$" } @@ -1609,7 +1608,7 @@ func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" } func (b *Buffer) bar() { // ERROR "leaking param: b$" - b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$" + b.buf1 = b.arr[1:2] } func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" @@ -1644,7 +1643,7 @@ type StructWithString struct { func fieldFlowTracking() { var x StructWithString i := 0 // ERROR "moved to heap: i$" - x.p = &i // ERROR "&i escapes to heap$" + x.p = &i sink = x.s // ERROR "x.s escapes to heap$" } @@ -1806,7 +1805,7 @@ func issue10353() { issue10353a(x)() } -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" +func issue10353a(x *int) func() { // ERROR "leaking param: x$" return func() { // ERROR "func literal escapes to heap$" println(*x) } @@ -1836,11 +1835,11 @@ func issue12397(x, y int) { // ERROR "moved to heap: y$" if false { gxx = &x } else { - gxx = &y // ERROR "&y escapes to heap$" + gxx = &y } if true { - gxx = &y // ERROR "&y escapes to heap$" + gxx = &y } else { gxx = &x } diff --git a/test/escape4.go b/test/escape4.go index 0fe33053..a4a9c14a 100644 --- a/test/escape4.go +++ b/test/escape4.go @@ -12,22 +12,22 @@ package foo var p *int func alloc(x int) *int { // ERROR "can inline alloc" "moved to heap: x" - return &x // ERROR "&x escapes to heap" + return &x } var f func() func f1() { - p = alloc(2) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x" + p = alloc(2) // ERROR "inlining call to alloc" "moved to heap: x" // Escape analysis used to miss inlined code in closures. func() { // ERROR "can inline f1.func1" p = alloc(3) // ERROR "inlining call to alloc" - }() // ERROR "inlining call to f1.func1" "inlining call to alloc" "&x escapes to heap" "moved to heap: x" + }() // ERROR "inlining call to f1.func1" "inlining call to alloc" "moved to heap: x" f = func() { // ERROR "func literal escapes to heap" "can inline f1.func2" - p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x" + p = alloc(3) // ERROR "inlining call to alloc" "moved to heap: x" } f() } @@ -43,7 +43,7 @@ func f5() *byte { x [1]byte } t := new(T) // ERROR "new.T. escapes to heap" - return &t.x[0] // ERROR "&t.x.0. escapes to heap" + return &t.x[0] } func f6() *byte { @@ -53,5 +53,5 @@ func f6() *byte { } } t := new(T) // ERROR "new.T. escapes to heap" - return &t.x.y // ERROR "&t.x.y escapes to heap" + return &t.x.y } diff --git a/test/escape5.go b/test/escape5.go index e26ecd52..11cab629 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -9,7 +9,10 @@ package foo -import "runtime" +import ( + "runtime" + "unsafe" +) func noleak(p *int) int { // ERROR "p does not escape" return *p @@ -60,37 +63,37 @@ func leaktosink(p *int) *int { // ERROR "leaking param: p" func f1() { var x int - p := noleak(&x) // ERROR "&x does not escape" + p := noleak(&x) _ = p } func f2() { var x int - p := leaktoret(&x) // ERROR "&x does not escape" + p := leaktoret(&x) _ = p } func f3() { - var x int // ERROR "moved to heap: x" - p := leaktoret(&x) // ERROR "&x escapes to heap" + var x int // ERROR "moved to heap: x" + p := leaktoret(&x) gp = p } func f4() { - var x int // ERROR "moved to heap: x" - p, q := leaktoret2(&x) // ERROR "&x escapes to heap" + var x int // ERROR "moved to heap: x" + p, q := leaktoret2(&x) gp = p gp = q } func f5() { var x int - leaktoret22(leaktoret2(&x)) // ERROR "&x does not escape" + leaktoret22(leaktoret2(&x)) } func f6() { - var x int // ERROR "moved to heap: x" - px1, px2 := leaktoret22(leaktoret2(&x)) // ERROR "&x escapes to heap" + var x int // ERROR "moved to heap: x" + px1, px2 := leaktoret22(leaktoret2(&x)) gp = px1 _ = px2 } @@ -129,7 +132,7 @@ type T2 struct { Y *T1 } -func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p" +func f8(p *T1) (k T2) { // ERROR "leaking param: p$" if p == nil { k = T2{} return @@ -142,7 +145,7 @@ func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: func f9() { var j T1 // ERROR "moved to heap: j" - f8(&j) // ERROR "&j escapes to heap" + f8(&j) } func f10() { @@ -159,8 +162,8 @@ func f12(_ **int) { } func f13() { var x *int - f11(&x) // ERROR "&x does not escape" - f12(&x) // ERROR "&x does not escape" + f11(&x) + f12(&x) runtime.KeepAlive(&x) // ERROR "&x does not escape" } @@ -172,8 +175,8 @@ func (_ *U) N() {} func _() { var u U - u.M() // ERROR "u does not escape" - u.N() // ERROR "u does not escape" + u.M() + u.N() } // Issue 24730: taking address in a loop causes unnecessary escape @@ -182,15 +185,15 @@ type T24730 struct { } 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 := t.x[:] + for i := range t.x[:] { + y = t.x[:] 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" + for i := range t.x[:] { + z = &t.x[i] *z = 2 } } @@ -245,3 +248,17 @@ func g29000() { x := 1 f29000(2, x) // ERROR "x escapes to heap" } + +// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an +// unnecessary escape. + +var sink28369 uintptr + +func f28369(n int) int { + if n == 0 { + sink28369 = uintptr(unsafe.Pointer(&n)) + return n + } + + return 1 + f28369(n-1) +} diff --git a/test/escape_array.go b/test/escape_array.go index c2c3e2c8..d363b98e 100644 --- a/test/escape_array.go +++ b/test/escape_array.go @@ -26,17 +26,17 @@ func bff(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "l func tbff1() *string { a := "cat" - b := "dog" // ERROR "moved to heap: b$" - u := bff(&a, &b) // ERROR "tbff1 &a does not escape$" "tbff1 &b does not escape$" + b := "dog" // ERROR "moved to heap: b$" + u := bff(&a, &b) _ = u[0] - return &b // ERROR "&b escapes to heap$" + return &b } // BAD: need fine-grained analysis to track u[0] and u[1] differently. func tbff2() *string { - a := "cat" // ERROR "moved to heap: a$" - b := "dog" // ERROR "moved to heap: b$" - u := bff(&a, &b) // ERROR "&a escapes to heap$" "&b escapes to heap$" + a := "cat" // ERROR "moved to heap: a$" + b := "dog" // ERROR "moved to heap: b$" + u := bff(&a, &b) _ = u[0] return u[1] } @@ -71,7 +71,7 @@ func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r2 level=1$ // pointers stored in small array literals do not escape; // large array literals are heap allocated; // pointers stored in large array literals escape. -func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "hugeLeaks1 y does not escape" "mark escaped content: x" +func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "hugeLeaks1 y does not escape" a := [10]*string{*y} _ = a // 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger. diff --git a/test/escape_because.go b/test/escape_because.go index 64fa28dd..e0a4214e 100644 --- a/test/escape_because.go +++ b/test/escape_because.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -m -l +// errorcheck -0 -m -m -l -newescape=false // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -40,7 +40,7 @@ func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "fr 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$" + sink = &u // ERROR "&u escapes to heap$" "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" @@ -78,7 +78,7 @@ func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go 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$" + return f8(*y, &x) } 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$" @@ -86,7 +86,7 @@ func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at esc 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$" + return f9(*y[0], &x) // ERROR "f9 ... argument does not escape$" } 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$" @@ -132,14 +132,14 @@ func leakThroughOAS2() { // See #26987. i := 0 // ERROR "moved to heap: i$" j := 0 // ERROR "moved to heap: j$" - sink, sink = &i, &j // ERROR "&i escapes to heap$" "from sink \(assign-pair\) at escape_because.go:135$" "from &i \(interface-converted\) at escape_because.go:135$" "&j escapes to heap$" "from &j \(interface-converted\) at escape_because.go:135" + sink, sink = &i, &j // ERROR "&i escapes to heap$" "from sink \(assign-pair\) at escape_because.go:135$" "&j escapes to heap$" } func leakThroughOAS2FUNC() { // See #26987. i := 0 // ERROR "moved to heap: i$" j := 0 - sink, _ = leakParams(&i, &j) // ERROR "&i escapes to heap$" "&j does not escape$" "from .out0 \(passed-to-and-returned-from-call\) at escape_because.go:142$" "from sink \(assign-pair-func-call\) at escape_because.go:142$" + sink, _ = leakParams(&i, &j) } // The list below is all of the why-escapes messages seen building the escape analysis tests. diff --git a/test/escape_calls.go b/test/escape_calls.go index 20cb6433..53f14dff 100644 --- a/test/escape_calls.go +++ b/test/escape_calls.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -19,7 +19,7 @@ func g(*byte) string func h(e int) { var x [32]byte // ERROR "moved to heap: x$" - g(&f(x[:])[0]) // ERROR "&f\(x\[:\]\)\[0\] escapes to heap$" "x escapes to heap$" + g(&f(x[:])[0]) } type Node struct { @@ -33,10 +33,10 @@ func walk(np **Node) int { // ERROR "leaking param content: np" if n == nil { return 0 } - wl := walk(&n.left) // ERROR "walk &n.left does not escape" - wr := walk(&n.right) // ERROR "walk &n.right does not escape" + wl := walk(&n.left) + wr := walk(&n.right) if wl < wr { - n.left, n.right = n.right, n.left + n.left, n.right = n.right, n.left // ERROR "ignoring self-assignment" wl, wr = wr, wl } *np = n diff --git a/test/escape_closure.go b/test/escape_closure.go index fc35cb59..cf055d3b 100644 --- a/test/escape_closure.go +++ b/test/escape_closure.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,30 +11,27 @@ package escape var sink interface{} func ClosureCallArgs0() { - x := 0 // ERROR "moved to heap: x" + x := 0 func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs1() { - x := 0 // ERROR "moved to heap: x" + x := 0 for { func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here - }(&x) // ERROR "&x escapes to heap" + }(&x) } } func ClosureCallArgs2() { for { - // BAD: x should not escape here - x := 0 // ERROR "moved to heap: x" + x := 0 func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - }(&x) // ERROR "&x escapes to heap" + }(&x) } } @@ -42,29 +39,30 @@ func ClosureCallArgs3() { x := 0 // ERROR "moved to heap: x" func(p *int) { // ERROR "leaking param: p" "func literal does not escape" sink = p // ERROR "p escapes to heap" - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs4() { - // BAD: x should not leak here - x := 0 // ERROR "moved to heap: x" + x := 0 _ = 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) } func ClosureCallArgs5() { x := 0 // ERROR "moved to heap: x" - sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" + // TODO(mdempsky): We get "leaking param: p" here because the new escape analysis pass + // can tell that p flows directly to sink, but it's a little weird. Re-evaluate. + sink = func(p *int) *int { // ERROR "leaking param: p" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" return p - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs6() { x := 0 // ERROR "moved to heap: x" func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" sink = &p // ERROR "&p escapes to heap" - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs7() { @@ -73,17 +71,16 @@ func ClosureCallArgs7() { x := 0 // ERROR "moved to heap: x" func(p *int) { // ERROR "leaking param: p" "func literal does not escape" pp = p - }(&x) // ERROR "&x escapes to heap" + }(&x) } _ = pp } func ClosureCallArgs8() { - x := 0 // ERROR "moved to heap: x" + x := 0 defer func(p *int) { // ERROR "p does not escape" "func literal does not escape" *p = 1 - // BAD: x should not escape to heap here - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs9() { @@ -92,7 +89,7 @@ func ClosureCallArgs9() { for { defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" *p = 1 - }(&x) // ERROR "&x escapes to heap" + }(&x) } } @@ -101,7 +98,7 @@ func ClosureCallArgs10() { x := 0 // ERROR "moved to heap: x" defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" *p = 1 - }(&x) // ERROR "&x escapes to heap" + }(&x) } } @@ -109,41 +106,37 @@ func ClosureCallArgs11() { x := 0 // ERROR "moved to heap: x" defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape" sink = p // ERROR "p escapes to heap" - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs12() { - // BAD: x should not leak - x := 0 // ERROR "moved to heap: x" + x := 0 defer 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) } func ClosureCallArgs13() { x := 0 // ERROR "moved to heap: x" defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" sink = &p // ERROR "&p escapes to heap" - }(&x) // ERROR "&x escapes to heap" + }(&x) } func ClosureCallArgs14() { - x := 0 // ERROR "moved to heap: x" - // BAD: &x should not escape here - p := &x // ERROR "moved to heap: p" "&x escapes to heap" + x := 0 + p := &x _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" return *p - // BAD: p should not escape here - }(&p) // ERROR "&p escapes to heap" + }(&p) } func ClosureCallArgs15() { x := 0 // ERROR "moved to heap: x" - p := &x // ERROR "moved to heap: p" "&x escapes to heap" - sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" + p := &x + sink = func(p **int) *int { // ERROR "leaking param content: p" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" return *p - // BAD: p should not escape here - }(&p) // ERROR "&p escapes to heap" + }(&p) } func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" @@ -152,7 +145,7 @@ func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" } // See #14409 -- returning part of captured var leaks it. -func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1$" return func() string { // ERROR "ClosureLeak1a func literal does not escape" return a[0] }() @@ -163,11 +156,11 @@ func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" return c } -func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" +func ClosureLeak2a(a ...string) string { // ERROR "leaking param content: a" return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" return a[0] }) } -func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" +func ClosureLeak2b(f func() string) string { // ERROR "ClosureLeak2b f does not escape" return f() } diff --git a/test/escape_field.go b/test/escape_field.go index e8835ae6..5d5a6f36 100644 --- a/test/escape_field.go +++ b/test/escape_field.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -23,7 +23,7 @@ type Y struct { func field0() { i := 0 // ERROR "moved to heap: i$" var x X - x.p1 = &i // ERROR "&i escapes to heap$" + x.p1 = &i sink = x.p1 // ERROR "x\.p1 escapes to heap" } @@ -31,21 +31,21 @@ func field1() { i := 0 // ERROR "moved to heap: i$" var x X // BAD: &i should not escape - x.p1 = &i // ERROR "&i escapes to heap$" + x.p1 = &i 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$" + x.p1 = &i sink = x // ERROR "x escapes to heap" } func field4() { i := 0 // ERROR "moved to heap: i$" var y Y - y.x.p1 = &i // ERROR "&i escapes to heap$" + y.x.p1 = &i x := y.x sink = x // ERROR "x escapes to heap" } @@ -54,7 +54,7 @@ func field5() { i := 0 // ERROR "moved to heap: i$" var x X // BAD: &i should not escape here - x.a[0] = &i // ERROR "&i escapes to heap$" + x.a[0] = &i sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap" } @@ -67,14 +67,14 @@ func field6a() { i := 0 // ERROR "moved to heap: i$" var x X // BAD: &i should not escape - x.p1 = &i // ERROR "&i escapes to heap$" - field6(&x) // ERROR "field6a &x does not escape" + x.p1 = &i + field6(&x) } func field7() { i := 0 var y Y - y.x.p1 = &i // ERROR "field7 &i does not escape$" + y.x.p1 = &i x := y.x var y1 Y y1.x = x @@ -84,7 +84,7 @@ func field7() { func field8() { i := 0 // ERROR "moved to heap: i$" var y Y - y.x.p1 = &i // ERROR "&i escapes to heap$" + y.x.p1 = &i x := y.x var y1 Y y1.x = x @@ -94,7 +94,7 @@ func field8() { func field9() { i := 0 // ERROR "moved to heap: i$" var y Y - y.x.p1 = &i // ERROR "&i escapes to heap$" + y.x.p1 = &i x := y.x var y1 Y y1.x = x @@ -105,7 +105,7 @@ func field10() { i := 0 // ERROR "moved to heap: i$" var y Y // BAD: &i should not escape - y.x.p1 = &i // ERROR "&i escapes to heap$" + y.x.p1 = &i x := y.x var y1 Y y1.x = x @@ -114,33 +114,33 @@ func field10() { func field11() { i := 0 // ERROR "moved to heap: i$" - x := X{p1: &i} // ERROR "&i escapes to heap$" + x := X{p1: &i} 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$" + x := X{p1: &i} 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$" + x := &X{p1: &i} // ERROR "field13 &X literal does not escape$" 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$" + x := &X{p1: &i} // ERROR "field14 &X literal does not escape$" 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$" + x := &X{p1: &i} // ERROR "&X literal escapes to heap$" sink = x // ERROR "x escapes to heap" } @@ -148,8 +148,8 @@ func field16() { i := 0 // ERROR "moved to heap: i$" var x X // BAD: &i should not escape - x.p1 = &i // ERROR "&i escapes to heap$" - var iface interface{} = x // ERROR "x escapes to heap" + x.p1 = &i + var iface interface{} = x // ERROR "field16 x does not escape" x1 := iface.(X) sink = x1.p2 // ERROR "x1\.p2 escapes to heap" } @@ -157,8 +157,8 @@ func field16() { func field17() { i := 0 // ERROR "moved to heap: i$" var x X - x.p1 = &i // ERROR "&i escapes to heap$" - var iface interface{} = x // ERROR "x escapes to heap" + x.p1 = &i + var iface interface{} = x // ERROR "field17 x does not escape" x1 := iface.(X) sink = x1.p1 // ERROR "x1\.p1 escapes to heap" } @@ -167,8 +167,8 @@ func field18() { i := 0 // ERROR "moved to heap: i$" var x X // BAD: &i should not escape - x.p1 = &i // ERROR "&i escapes to heap$" - var iface interface{} = x // ERROR "x escapes to heap" + x.p1 = &i + var iface interface{} = x // ERROR "field18 x does not escape" y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized. sink = y // ERROR "y escapes to heap" } diff --git a/test/escape_iface.go b/test/escape_iface.go index 8a11d7eb..50c69cd5 100644 --- a/test/escape_iface.go +++ b/test/escape_iface.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -32,26 +32,26 @@ func (M0) M() { func efaceEscape0() { { i := 0 - v := M0{&i} // ERROR "&i does not escape" + v := M0{&i} 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" + v := M0{&i} 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" + v := M0{&i} 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" + v := M0{&i} // BAD: v does not escape to heap here var x M = v // ERROR "v escapes to heap" v1 := x.(M0) @@ -59,20 +59,20 @@ func efaceEscape0() { } { i := 0 // ERROR "moved to heap: i" - v := M0{&i} // ERROR "&i escapes to heap" + v := M0{&i} // 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" + v := M0{&i} var x M = v // ERROR "v escapes to heap" mescapes(x) } { i := 0 - v := M0{&i} // ERROR "&i does not escape" + v := M0{&i} var x M = v // ERROR "v does not escape" mdoesnotescape(x) } @@ -90,47 +90,46 @@ func (M1) M() { func efaceEscape1() { { i := 0 - v := M1{&i, 0} // ERROR "&i does not escape" + v := M1{&i, 0} 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" + v := M1{&i, 0} 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" + v := M1{&i, 0} 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" + v := M1{&i, 0} + var x M = v // ERROR "efaceEscape1 v does not escape" 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" + v := M1{&i, 0} // 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" + v := M1{&i, 0} var x M = v // ERROR "v escapes to heap" mescapes(x) } { i := 0 - v := M1{&i, 0} // ERROR "&i does not escape" + v := M1{&i, 0} var x M = v // ERROR "v does not escape" mdoesnotescape(x) } @@ -147,26 +146,26 @@ func (*M2) M() { func efaceEscape2() { { i := 0 - v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape" + v := &M2{&i} // ERROR "&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" + v := &M2{&i} // ERROR "&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" + v := &M2{&i} // ERROR "&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" + v := &M2{&i} // ERROR "&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) @@ -174,7 +173,7 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape" + v := &M2{&i} // ERROR "&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) @@ -182,7 +181,7 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape" + v := &M2{&i} // ERROR "&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) @@ -191,20 +190,20 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap" + v := &M2{&i} // ERROR "&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" + v := &M2{&i} // ERROR "&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" + v := &M2{&i} // ERROR "&M2 literal does not escape" var x M = v // ERROR "v does not escape" mdoesnotescape(x) } @@ -235,8 +234,8 @@ func dotTypeEscape2() { // #13805, #15796 var x interface{} = i // ERROR "i does not escape" var y interface{} = j // ERROR "j does not escape" - *(&v) = x.(int) // ERROR "&v does not escape" - *(&v), *(&ok) = y.(int) // ERROR "&v does not escape" "&ok does not escape" + *(&v) = x.(int) + *(&v), *(&ok) = y.(int) } { i := 0 @@ -246,7 +245,7 @@ func dotTypeEscape2() { // #13805, #15796 var y interface{} = j // ERROR "j does not escape" sink = x.(int) // ERROR "x.\(int\) escapes to heap" - sink, *(&ok) = y.(int) // ERROR "&ok does not escape" + sink, *(&ok) = y.(int) } { i := 0 // ERROR "moved to heap: i" @@ -256,6 +255,6 @@ func dotTypeEscape2() { // #13805, #15796 var y interface{} = &j // ERROR "&j escapes to heap" sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" - sink, *(&ok) = y.(*int) // ERROR "&ok does not escape" + sink, *(&ok) = y.(*int) } } diff --git a/test/escape_indir.go b/test/escape_indir.go index aac4e675..ce21ea82 100644 --- a/test/escape_indir.go +++ b/test/escape_indir.go @@ -25,42 +25,42 @@ func constptr0() { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" // BAD: i should not escape here - x.p = &i // ERROR "&i escapes to heap" + x.p = &i _ = x } func constptr01() *ConstPtr { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" - x.p = &i // ERROR "&i escapes to heap" + x.p = &i return x } func constptr02() ConstPtr { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" - x.p = &i // ERROR "&i escapes to heap" + x.p = &i return *x } func constptr03() **ConstPtr { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" "moved to heap: x" - x.p = &i // ERROR "&i escapes to heap" - return &x // ERROR "&x escapes to heap" + x.p = &i + return &x } func constptr1() { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" - x.p = &i // ERROR "&i escapes to heap" + x.p = &i 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" + x.p = &i sink = *x // ERROR "\*x escapes to heap" } @@ -87,15 +87,15 @@ func constptr6(p *ConstPtr) { // ERROR "leaking param content: p" func constptr7() **ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" "moved to heap: p" var tmp ConstPtr2 - p1 := &tmp // ERROR "&tmp does not escape" + p1 := &tmp p.c = *p1 - return &p // ERROR "&p escapes to heap" + return &p } func constptr8() *ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" var tmp ConstPtr2 - p.c = *&tmp // ERROR "&tmp does not escape" + p.c = *&tmp return p } @@ -103,7 +103,7 @@ func constptr9() ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) does not escape" var p1 ConstPtr2 i := 0 // ERROR "moved to heap: i" - p1.p = &i // ERROR "&i escapes to heap" + p1.p = &i p.c = p1 return *p } @@ -112,9 +112,9 @@ func constptr10() ConstPtr { x := &ConstPtr{} // ERROR "moved to heap: x" "&ConstPtr literal escapes to heap" i := 0 // ERROR "moved to heap: i" var p *ConstPtr - p = &ConstPtr{p: &i, x: &x} // ERROR "&i escapes to heap" "&x escapes to heap" "&ConstPtr literal does not escape" + p = &ConstPtr{p: &i, x: &x} // ERROR "&ConstPtr literal does not escape" var pp **ConstPtr - pp = &p // ERROR "&p does not escape" + pp = &p return **pp } @@ -122,7 +122,7 @@ func constptr11() *ConstPtr { i := 0 // ERROR "moved to heap: i" p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" - p1.p = &i // ERROR "&i escapes to heap" + p1.p = &i *p = *p1 return p } @@ -130,13 +130,13 @@ func constptr11() *ConstPtr { func foo(p **int) { // ERROR "foo p does not escape" i := 0 // ERROR "moved to heap: i" y := p - *y = &i // ERROR "&i escapes to heap" + *y = &i } func foo1(p *int) { // ERROR "p does not escape" i := 0 // ERROR "moved to heap: i" - y := &p // ERROR "&p does not escape" - *y = &i // ERROR "&i escapes to heap" + y := &p + *y = &i } func foo2() { @@ -146,15 +146,15 @@ func foo2() { x := new(int) // ERROR "moved to heap: x" "new\(int\) escapes to heap" sink = &x // ERROR "&x escapes to heap" var z Z - z.f = &x // ERROR "&x does not escape" + z.f = &x p := z.f i := 0 // ERROR "moved to heap: i" - *p = &i // ERROR "&i escapes to heap" + *p = &i } var global *byte func f() { var x byte // ERROR "moved to heap: x" - global = &*&x // ERROR "&\(\*\(&x\)\) escapes to heap" "&x escapes to heap" + global = &*&x } diff --git a/test/escape_level.go b/test/escape_level.go index 490f615f..44a23e5a 100644 --- a/test/escape_level.go +++ b/test/escape_level.go @@ -12,64 +12,64 @@ var sink interface{} func level0() { i := 0 // ERROR "moved to heap: i" - 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 "moved to heap: p2" "&p1 escapes to heap" + p0 := &i // ERROR "moved to heap: p0" + p1 := &p0 // ERROR "moved to heap: p1" + p2 := &p1 // ERROR "moved to heap: p2" sink = &p2 // ERROR "&p2 escapes to heap" } func level1() { i := 0 // ERROR "moved to heap: i" - 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" + p0 := &i // ERROR "moved to heap: p0" + p1 := &p0 // ERROR "moved to heap: p1" + p2 := &p1 sink = p2 // ERROR "p2 escapes to heap" } func level2() { i := 0 // ERROR "moved to heap: i" - 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" + p0 := &i // ERROR "moved to heap: p0" + p1 := &p0 + p2 := &p1 sink = *p2 // ERROR "\*p2 escapes to heap" } func level3() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "&i escapes to heap" - p1 := &p0 // ERROR "&p0 does not escape" - p2 := &p1 // ERROR "&p1 does not escape" + p0 := &i + p1 := &p0 + p2 := &p1 sink = **p2 // ERROR "\* \(\*p2\) escapes to heap" } func level4() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "moved to heap: p0" "&i escapes to heap" - p1 := &p0 // ERROR "&p0 escapes to heap" + p0 := &i // ERROR "moved to heap: p0" + p1 := &p0 p2 := p1 // ERROR "moved to heap: p2" sink = &p2 // ERROR "&p2 escapes to heap" } func level5() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "moved to heap: p0" "&i escapes to heap" - p1 := &p0 // ERROR "&p0 escapes to heap" + p0 := &i // ERROR "moved to heap: p0" + p1 := &p0 p2 := p1 sink = p2 // ERROR "p2 escapes to heap" } func level6() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "&i escapes to heap" - p1 := &p0 // ERROR "&p0 does not escape" + p0 := &i + p1 := &p0 p2 := p1 sink = *p2 // ERROR "\*p2 escapes to heap" } func level7() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "&i escapes to heap" - p1 := &p0 // ERROR "&p0 does not escape" + p0 := &i + p1 := &p0 // note *p1 == &i p2 := *p1 // ERROR "moved to heap: p2" sink = &p2 // ERROR "&p2 escapes to heap" @@ -77,32 +77,32 @@ func level7() { func level8() { i := 0 // ERROR "moved to heap: i" - p0 := &i // ERROR "&i escapes to heap" - p1 := &p0 // ERROR "&p0 does not escape" + p0 := &i + p1 := &p0 p2 := *p1 sink = p2 // ERROR "p2 escapes to heap" } func level9() { i := 0 - p0 := &i // ERROR "&i does not escape" - p1 := &p0 // ERROR "&p0 does not escape" + p0 := &i + p1 := &p0 p2 := *p1 sink = *p2 // ERROR "\*p2 escapes to heap" } func level10() { i := 0 - p0 := &i // ERROR "&i does not escape" + p0 := &i p1 := *p0 - p2 := &p1 // ERROR "&p1 does not escape" + p2 := &p1 sink = *p2 // ERROR "\*p2 escapes to heap" } func level11() { i := 0 - p0 := &i // ERROR "&i does not escape" - p1 := &p0 // ERROR "&p0 does not escape" + p0 := &i + p1 := &p0 p2 := **p1 // ERROR "moved to heap: p2" sink = &p2 // ERROR "&p2 escapes to heap" } diff --git a/test/escape_map.go b/test/escape_map.go index 99cbd482..9912b55a 100644 --- a/test/escape_map.go +++ b/test/escape_map.go @@ -16,7 +16,7 @@ func map0() { i := 0 // ERROR "moved to heap: i" // BAD: j should not escape j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j _ = m } @@ -25,15 +25,15 @@ func map1() *int { // BAD: i should not escape i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" - return m[&i] // ERROR "&i does not escape" + m[&i] = &j + return m[&i] } func map2() map[*int]*int { m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) escapes to heap" i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j return m } @@ -42,7 +42,7 @@ func map3() []*int { i := 0 // ERROR "moved to heap: i" // BAD: j should not escape j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j var r []*int for k := range m { r = append(r, k) @@ -55,7 +55,7 @@ func map4() []*int { // BAD: i should not escape i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j var r []*int for k, v := range m { // We want to test exactly "for k, v := range m" rather than "for _, v := range m". @@ -70,7 +70,7 @@ func map4() []*int { func map5(m map[*int]*int) { // ERROR "m does not escape" i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j } func map6(m map[*int]*int) { // ERROR "m does not escape" @@ -79,7 +79,7 @@ func map6(m map[*int]*int) { // ERROR "m does not escape" } i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap" + m[&i] = &j } func map7() { @@ -87,14 +87,14 @@ func map7() { i := 0 // ERROR "moved to heap: i" // BAD: j should not escape j := 0 // ERROR "moved to heap: j" - m := map[*int]*int{&i: &j} // ERROR "&i escapes to heap" "&j escapes to heap" "literal does not escape" + m := map[*int]*int{&i: &j} // ERROR "literal does not escape" _ = m } func map8() { 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" + m := map[*int]*int{&i: &j} // ERROR "literal escapes to heap" sink = m // ERROR "m escapes to heap" } @@ -102,6 +102,6 @@ func map9() *int { // BAD: i should not escape 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 does not escape" + m := map[*int]*int{&i: &j} // ERROR "literal does not escape" return m[nil] } diff --git a/test/escape_param.go b/test/escape_param.go index 175a4f03..20975567 100644 --- a/test/escape_param.go +++ b/test/escape_param.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -22,12 +22,12 @@ func param0(p *int) *int { // ERROR "leaking param: p to result ~r1" func caller0a() { i := 0 - _ = param0(&i) // ERROR "caller0a &i does not escape$" + _ = param0(&i) } func caller0b() { i := 0 // ERROR "moved to heap: i$" - sink = param0(&i) // ERROR "&i escapes to heap$" "param0\(&i\) escapes to heap" + sink = param0(&i) // ERROR "param0\(&i\) escapes to heap" } // in, in -> out, out @@ -38,7 +38,7 @@ func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r func caller1() { i := 0 // ERROR "moved to heap: i$" j := 0 - sink, _ = param1(&i, &j) // ERROR "&i escapes to heap$" "caller1 &j does not escape$" + sink, _ = param1(&i, &j) } // in -> other in @@ -49,14 +49,14 @@ func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does n func caller2a() { i := 0 // ERROR "moved to heap: i$" var p *int - param2(&i, &p) // ERROR "&i escapes to heap$" "caller2a &p does not escape$" + param2(&i, &p) _ = p } func caller2b() { i := 0 // ERROR "moved to heap: i$" var p *int - param2(&i, &p) // ERROR "&i escapes to heap$" "caller2b &p does not escape$" + param2(&i, &p) sink = p // ERROR "p escapes to heap$" } @@ -144,16 +144,16 @@ func param3(p *Pair) { // ERROR "param3 p does not escape" func caller3a() { i := 0 j := 0 - p := Pair{&i, &j} // ERROR "caller3a &i does not escape" "caller3a &j does not escape" - param3(&p) // ERROR "caller3a &p does not escape" + p := Pair{&i, &j} + param3(&p) _ = p } func caller3b() { i := 0 // ERROR "moved to heap: i$" j := 0 // ERROR "moved to heap: j$" - p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$" - param3(&p) // ERROR "caller3b &p does not escape" + p := Pair{&i, &j} + param3(&p) sink = p // ERROR "p escapes to heap$" } @@ -165,14 +165,14 @@ func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" func caller4a() { i := 0 // ERROR "moved to heap: i$" p := Pair{} - p.param4(&i) // ERROR "&i escapes to heap$" "caller4a p does not escape$" + p.param4(&i) _ = p } func caller4b() { i := 0 // ERROR "moved to heap: i$" p := Pair{} - p.param4(&i) // ERROR "&i escapes to heap$" "caller4b p does not escape$" + p.param4(&i) sink = p // ERROR "p escapes to heap$" } @@ -183,7 +183,7 @@ func param5(i *int) { // ERROR "leaking param: i$" func caller5() { i := 0 // ERROR "moved to heap: i$" - param5(&i) // ERROR "&i escapes to heap$" + param5(&i) } // *in -> heap @@ -193,9 +193,9 @@ func param6(i ***int) { // ERROR "leaking param content: i$" func caller6a() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" - p2 := &p // ERROR "&p escapes to heap$" - param6(&p2) // ERROR "caller6a &p2 does not escape" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param6(&p2) } // **in -> heap @@ -205,9 +205,9 @@ func param7(i ***int) { // ERROR "leaking param content: i$" func caller7() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" - p2 := &p // ERROR "&p escapes to heap$" - param7(&p2) // ERROR "caller7 &p2 does not escape" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param7(&p2) } // **in -> heap @@ -217,8 +217,8 @@ func param8(i **int) { // ERROR "param8 i does not escape$" func caller8() { i := 0 - p := &i // ERROR "caller8 &i does not escape$" - param8(&p) // ERROR "caller8 &p does not escape$" + p := &i + param8(&p) } // *in -> out @@ -228,16 +228,16 @@ func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1" func caller9a() { i := 0 - p := &i // ERROR "caller9a &i does not escape" - p2 := &p // ERROR "caller9a &p does not escape" - _ = param9(&p2) // ERROR "caller9a &p2 does not escape$" + p := &i + p2 := &p + _ = param9(&p2) } func caller9b() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" - p2 := &p // ERROR "&p escapes to heap$" - sink = param9(&p2) // ERROR "caller9b &p2 does not escape$" "param9\(&p2\) escapes to heap" + p := &i // ERROR "moved to heap: p$" + p2 := &p + sink = param9(&p2) // ERROR "param9\(&p2\) escapes to heap" } // **in -> out @@ -247,45 +247,45 @@ func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2" func caller10a() { i := 0 - p := &i // ERROR "caller10a &i does not escape" - p2 := &p // ERROR "caller10a &p does not escape" - _ = param10(&p2) // ERROR "caller10a &p2 does not escape$" + p := &i + p2 := &p + _ = param10(&p2) } func caller10b() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" - p2 := &p // ERROR "caller10b &p does not escape$" - sink = param10(&p2) // ERROR "caller10b &p2 does not escape$" "param10\(&p2\) escapes to heap" + p := &i + p2 := &p + sink = param10(&p2) // ERROR "param10\(&p2\) escapes to heap" } // in escapes to heap (address of param taken and returned) func param11(i **int) ***int { // ERROR "moved to heap: i$" - return &i // ERROR "&i escapes to heap$" + return &i } func caller11a() { i := 0 // ERROR "moved to heap: i" - p := &i // ERROR "moved to heap: p" "&i escapes to heap" - _ = param11(&p) // ERROR "&p escapes to heap" + p := &i // ERROR "moved to heap: p" + _ = param11(&p) } func caller11b() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" - sink = param11(&p) // ERROR "&p escapes to heap$" "param11\(&p\) escapes to heap" + p := &i // ERROR "moved to heap: p$" + sink = param11(&p) // ERROR "param11\(&p\) escapes to heap" } func caller11c() { // GOOD i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p" "&i escapes to heap" - sink = *param11(&p) // ERROR "&p escapes to heap" "\*param11\(&p\) escapes to heap" + p := &i // ERROR "moved to heap: p" + sink = *param11(&p) // ERROR "\*param11\(&p\) escapes to heap" } func caller11d() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap" "moved to heap: p" - p2 := &p // ERROR "&p escapes to heap" + p := &i // ERROR "moved to heap: p" + p2 := &p sink = param11(p2) // ERROR "param11\(p2\) escapes to heap" } @@ -295,38 +295,38 @@ type Indir struct { } func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$" - r.p = &i // ERROR "&i escapes to heap$" + r.p = &i } func caller12a() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" + p := &i // ERROR "moved to heap: p$" var r Indir - r.param12(&p) // ERROR "&p escapes to heap$" "caller12a r does not escape$" + r.param12(&p) _ = r } func caller12b() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" + p := &i // ERROR "moved to heap: p$" r := &Indir{} // ERROR "caller12b &Indir literal does not escape$" - r.param12(&p) // ERROR "&p escapes to heap$" + r.param12(&p) _ = r } func caller12c() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" + p := &i // ERROR "moved to heap: p$" r := Indir{} - r.param12(&p) // ERROR "&p escapes to heap$" "caller12c r does not escape$" + r.param12(&p) sink = r // ERROR "r escapes to heap$" } func caller12d() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "&i escapes to heap$" "moved to heap: p$" + p := &i // ERROR "moved to heap: p$" r := Indir{} - r.param12(&p) // ERROR "&p escapes to heap$" "caller12d r does not escape$" + r.param12(&p) sink = **r.p // ERROR "\* \(\*r\.p\) escapes to heap" } @@ -343,24 +343,24 @@ func caller13a() { i := 0 // ERROR "moved to heap: i$" var p *int var v Val - v.p = &p // ERROR "caller13a &p does not escape$" - v.param13(&i) // ERROR "&i escapes to heap$" + v.p = &p + v.param13(&i) _ = v } func caller13b() { i := 0 // ERROR "moved to heap: i$" var p *int - v := Val{&p} // ERROR "caller13b &p does not escape$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := Val{&p} + v.param13(&i) _ = v } func caller13c() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" "caller13c &p does not escape$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" + v.param13(&i) _ = v } @@ -368,40 +368,40 @@ func caller13d() { i := 0 // ERROR "moved to heap: i$" var p *int // ERROR "moved to heap: p$" var v Val - v.p = &p // ERROR "&p escapes to heap$" - v.param13(&i) // ERROR "&i escapes to heap$" + v.p = &p + v.param13(&i) sink = v // ERROR "v escapes to heap$" } func caller13e() { i := 0 // ERROR "moved to heap: i$" var p *int // ERROR "moved to heap: p$" - v := Val{&p} // ERROR "&p escapes to heap$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := Val{&p} + v.param13(&i) sink = v // ERROR "v escapes to heap$" } func caller13f() { i := 0 // ERROR "moved to heap: i$" var p *int // ERROR "moved to heap: p$" - v := &Val{&p} // ERROR "&Val literal escapes to heap$" "&p escapes to heap$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := &Val{&p} // ERROR "&Val literal escapes to heap$" + v.param13(&i) sink = v // ERROR "v escapes to heap$" } func caller13g() { i := 0 // ERROR "moved to heap: i$" var p *int - v := Val{&p} // ERROR "caller13g &p does not escape$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := Val{&p} + v.param13(&i) sink = *v.p // ERROR "\*v\.p escapes to heap" } func caller13h() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" "caller13h &p does not escape$" - v.param13(&i) // ERROR "&i escapes to heap$" + v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" + v.param13(&i) sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" } @@ -415,7 +415,7 @@ func f(x *Node) { // ERROR "leaking param content: x" Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" } -func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0" +func g(x *Node) *Node { // ERROR "leaking param content: x" return &Node{x.p} // ERROR "&Node literal escapes to heap" } diff --git a/test/escape_runtime_atomic.go b/test/escape_runtime_atomic.go new file mode 100644 index 00000000..62e8fede --- /dev/null +++ b/test/escape_runtime_atomic.go @@ -0,0 +1,33 @@ +// errorcheck -0 -m -l + +// Copyright 2019 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 runtime/internal/atomic. + +package escape + +import ( + "runtime/internal/atomic" + "unsafe" +) + +// BAD: should always be "leaking param: addr to result ~r1 level=1$". +func Loadp(addr unsafe.Pointer) unsafe.Pointer { // ERROR "leaking param: addr( to result ~r1 level=1)?$" + return atomic.Loadp(addr) +} + +var ptr unsafe.Pointer + +func Storep() { + var x int // ERROR "moved to heap: x" + atomic.StorepNoWB(unsafe.Pointer(&ptr), unsafe.Pointer(&x)) +} + +func Casp1() { + // BAD: should always be "does not escape" + x := new(int) // ERROR "escapes to heap|does not escape" + var y int // ERROR "moved to heap: y" + atomic.Casp1(&ptr, unsafe.Pointer(x), unsafe.Pointer(&y)) +} diff --git a/test/escape_selfassign.go b/test/escape_selfassign.go new file mode 100644 index 00000000..b4fa2084 --- /dev/null +++ b/test/escape_selfassign.go @@ -0,0 +1,32 @@ +// errorcheck -0 -m -l + +// Copyright 2019 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 self assignments. + +package escape + +type S struct { + i int + pi *int +} + +var sink S + +func f(p *S) { // ERROR "leaking param: p" + p.pi = &p.i + sink = *p +} + +// BAD: "leaking param: p" is too conservative +func g(p *S) { // ERROR "leaking param: p" + p.pi = &p.i +} + +func h() { + var s S // ERROR "moved to heap: s" + g(&s) + sink = s +} diff --git a/test/escape_slice.go b/test/escape_slice.go index ffd7cdb5..03053cf3 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -19,28 +19,28 @@ func slice0() { var s []*int // BAD: i should not escape i := 0 // ERROR "moved to heap: i" - s = append(s, &i) // ERROR "&i escapes to heap" + s = append(s, &i) _ = s } func slice1() *int { var s []*int i := 0 // ERROR "moved to heap: i" - s = append(s, &i) // ERROR "&i escapes to heap" + s = append(s, &i) return s[0] } func slice2() []*int { var s []*int i := 0 // ERROR "moved to heap: i" - s = append(s, &i) // ERROR "&i escapes to heap" + s = append(s, &i) return s } func slice3() *int { var s []*int i := 0 // ERROR "moved to heap: i" - s = append(s, &i) // ERROR "&i escapes to heap" + s = append(s, &i) for _, p := range s { return p } @@ -49,7 +49,7 @@ func slice3() *int { func slice4(s []*int) { // ERROR "s does not escape" i := 0 // ERROR "moved to heap: i" - s[0] = &i // ERROR "&i escapes to heap" + s[0] = &i } func slice5(s []*int) { // ERROR "s does not escape" @@ -57,39 +57,39 @@ func slice5(s []*int) { // ERROR "s does not escape" s = make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" } i := 0 // ERROR "moved to heap: i" - s[0] = &i // ERROR "&i escapes to heap" + s[0] = &i } func slice6() { s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" // BAD: i should not escape i := 0 // ERROR "moved to heap: i" - s[0] = &i // ERROR "&i escapes to heap" + s[0] = &i _ = s } func slice7() *int { s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" i := 0 // ERROR "moved to heap: i" - s[0] = &i // ERROR "&i escapes to heap" + s[0] = &i return s[0] } func slice8() { i := 0 - s := []*int{&i} // ERROR "&i does not escape" "literal does not escape" + s := []*int{&i} // ERROR "literal does not escape" _ = s } func slice9() *int { i := 0 // ERROR "moved to heap: i" - s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape" + s := []*int{&i} // ERROR "literal does not escape" return s[0] } func slice10() []*int { i := 0 // ERROR "moved to heap: i" - s := []*int{&i} // ERROR "&i escapes to heap" "literal escapes to heap" + s := []*int{&i} // ERROR "literal escapes to heap" return s } diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go index 076fbc8c..7004946e 100644 --- a/test/escape_struct_param1.go +++ b/test/escape_struct_param1.go @@ -36,16 +36,16 @@ func (u *U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=2$" func tSPPi() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" - pps := &ps // ERROR "tSPPi &ps does not escape$" + ps := &s + pps := &ps pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$" Ssink = pu.SPPi() } func tiSPP() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" - pps := &ps // ERROR "tiSPP &ps does not escape$" + ps := &s + pps := &ps pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$" Ssink = *pu.SPP() } @@ -53,8 +53,8 @@ func tiSPP() { // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of ps func tSP() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" "moved to heap: ps$" - pps := &ps // ERROR "&ps escapes to heap$" + ps := &s // ERROR "moved to heap: ps$" + pps := &ps pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$" Ssink = pu.SP() } @@ -92,7 +92,7 @@ func (v *V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$ } func (v *V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$" - return v._u.SPPi() // ERROR "\(\*V\).USPPib v._u does not escape$" + return v._u.SPPi() } func (v *V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=2$" @@ -119,13 +119,13 @@ func tUPiSPa() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPa &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } @@ -137,13 +137,13 @@ func tUPiSPb() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPb &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } @@ -155,13 +155,13 @@ func tUPiSPc() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPc &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } @@ -173,13 +173,13 @@ func tUPiSPd() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPd &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -192,11 +192,11 @@ func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2 } func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$" - return *v.UP()._spp // ERROR "V.UPiSPPic v does not escape$" + return *v.UP()._spp } func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$" - return v.UP().SPPi() // ERROR "V.UPiSPPid v does not escape$" + return v.UP().SPPi() } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4 @@ -207,13 +207,13 @@ func tUPiSPPia() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPia &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPia &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -225,13 +225,13 @@ func tUPiSPPib() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPib &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPib &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -243,13 +243,13 @@ func tUPiSPPic() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPic &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPic &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -261,13 +261,13 @@ func tUPiSPPid() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPid &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPid &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -287,12 +287,12 @@ func tUPPiSPPia() { s4 := "dog" s5 := "emu" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPPiSPPia &s2 does not escape$" - ps4 := &s4 // ERROR "tUPPiSPPia &s4 does not escape$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" - u1 := U{&s1, &ps2} // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) } diff --git a/test/escape_struct_param2.go b/test/escape_struct_param2.go index d5305d4f..5a9b2719 100644 --- a/test/escape_struct_param2.go +++ b/test/escape_struct_param2.go @@ -36,16 +36,16 @@ func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$" func tSPPi() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" - pps := &ps // ERROR "tSPPi &ps does not escape$" + ps := &s + pps := &ps pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$" Ssink = pu.SPPi() } func tiSPP() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" - pps := &ps // ERROR "tiSPP &ps does not escape$" + ps := &s + pps := &ps pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$" Ssink = *pu.SPP() } @@ -53,8 +53,8 @@ func tiSPP() { // BAD: need fine-grained analysis to avoid spurious escape of ps func tSP() { s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "&s escapes to heap$" "moved to heap: ps$" - pps := &ps // ERROR "&ps escapes to heap$" + ps := &s // ERROR "moved to heap: ps$" + pps := &ps pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$" Ssink = pu.SP() } @@ -119,13 +119,13 @@ func tUPiSPa() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPa &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } @@ -137,13 +137,13 @@ func tUPiSPb() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPb &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } @@ -155,13 +155,13 @@ func tUPiSPc() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPc &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } @@ -173,13 +173,13 @@ func tUPiSPd() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "&s2 escapes to heap$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" "moved to heap: ps4$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPd &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -207,13 +207,13 @@ func tUPiSPPia() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPia &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPia &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -225,13 +225,13 @@ func tUPiSPPib() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPib &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPib &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -243,13 +243,13 @@ func tUPiSPPic() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPic &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPic &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -261,13 +261,13 @@ func tUPiSPPid() { s4 := "dog" // ERROR "moved to heap: s4$" s5 := "emu" // ERROR "moved to heap: s5$" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPiSPPid &s2 does not escape$" - ps4 := &s4 // ERROR "&s4 escapes to heap$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" "moved to heap: ps6$" - u1 := U{&s1, &ps2} // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 // ERROR "moved to heap: ps6$" + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPiSPPid &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -287,12 +287,12 @@ func tUPPiSPPia() { // This test is sensitive to the level cap in function summa s4 := "dog" s5 := "emu" s6 := "fox" // ERROR "moved to heap: s6$" - ps2 := &s2 // ERROR "tUPPiSPPia &s2 does not escape$" - ps4 := &s4 // ERROR "tUPPiSPPia &s4 does not escape$" - ps6 := &s6 // ERROR "&s6 escapes to heap$" - u1 := U{&s1, &ps2} // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$" - u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$" + ps2 := &s2 + ps4 := &s4 + ps6 := &s6 + u1 := U{&s1, &ps2} + u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" + u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) } diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go index 565f08ec..2b6de1c7 100644 --- a/test/escape_struct_return.go +++ b/test/escape_struct_return.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -19,14 +19,14 @@ func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 l return U{sp, spp} } -func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$" +func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" return U{*spp, spp} } func tA1() { s := "cat" - sp := &s // ERROR "tA1 &s does not escape$" - spp := &sp // ERROR "tA1 &sp does not escape$" + sp := &s + spp := &sp u := A(sp, spp) _ = u println(s) @@ -34,24 +34,24 @@ func tA1() { func tA2() { s := "cat" - sp := &s // ERROR "tA2 &s does not escape$" - spp := &sp // ERROR "tA2 &sp does not escape$" + sp := &s + spp := &sp u := A(sp, spp) println(*u._sp) } func tA3() { s := "cat" - sp := &s // ERROR "tA3 &s does not escape$" - spp := &sp // ERROR "tA3 &sp does not escape$" + sp := &s + spp := &sp u := A(sp, spp) println(**u._spp) } func tB1() { s := "cat" - sp := &s // ERROR "tB1 &s does not escape$" - spp := &sp // ERROR "tB1 &sp does not escape$" + sp := &s + spp := &sp u := B(spp) _ = u println(s) @@ -59,16 +59,16 @@ func tB1() { func tB2() { s := "cat" - sp := &s // ERROR "tB2 &s does not escape$" - spp := &sp // ERROR "tB2 &sp does not escape$" + sp := &s + spp := &sp u := B(spp) println(*u._sp) } func tB3() { s := "cat" - sp := &s // ERROR "tB3 &s does not escape$" - spp := &sp // ERROR "tB3 &sp does not escape$" + sp := &s + spp := &sp u := B(spp) println(**u._spp) } diff --git a/test/escape_sync_atomic.go b/test/escape_sync_atomic.go new file mode 100644 index 00000000..e509b375 --- /dev/null +++ b/test/escape_sync_atomic.go @@ -0,0 +1,38 @@ +// errorcheck -0 -m -l + +// Copyright 2019 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 sync/atomic. + +package escape + +import ( + "sync/atomic" + "unsafe" +) + +// BAD: should be "leaking param: addr to result ~r1 level=1$". +func LoadPointer(addr *unsafe.Pointer) unsafe.Pointer { // ERROR "leaking param: addr$" + return atomic.LoadPointer(addr) +} + +var ptr unsafe.Pointer + +func StorePointer() { + var x int // ERROR "moved to heap: x" + atomic.StorePointer(&ptr, unsafe.Pointer(&x)) +} + +func SwapPointer() { + var x int // ERROR "moved to heap: x" + atomic.SwapPointer(&ptr, unsafe.Pointer(&x)) +} + +func CompareAndSwapPointer() { + // BAD: x doesn't need to be heap allocated + var x int // ERROR "moved to heap: x" + var y int // ERROR "moved to heap: y" + atomic.CompareAndSwapPointer(&ptr, unsafe.Pointer(&x), unsafe.Pointer(&y)) +} diff --git a/test/escape_unsafe.go b/test/escape_unsafe.go new file mode 100644 index 00000000..16f14c07 --- /dev/null +++ b/test/escape_unsafe.go @@ -0,0 +1,69 @@ +// errorcheck -0 -m -l + +// Copyright 2019 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 unsafe.Pointer rules. + +package escape + +import ( + "reflect" + "unsafe" +) + +// (1) Conversion of a *T1 to Pointer to *T2. + +func convert(p *float64) *uint64 { // ERROR "leaking param: p to result ~r1 level=0$" + return (*uint64)(unsafe.Pointer(p)) +} + +// (3) Conversion of a Pointer to a uintptr and back, with arithmetic. + +func arithAdd() unsafe.Pointer { + var x [2]byte // ERROR "moved to heap: x" + return unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + 1) +} + +func arithSub() unsafe.Pointer { + var x [2]byte // ERROR "moved to heap: x" + return unsafe.Pointer(uintptr(unsafe.Pointer(&x[1])) - 1) +} + +func arithMask() unsafe.Pointer { + var x [2]byte // ERROR "moved to heap: x" + return unsafe.Pointer(uintptr(unsafe.Pointer(&x[1])) &^ 1) +} + +// (5) Conversion of the result of reflect.Value.Pointer or +// reflect.Value.UnsafeAddr from uintptr to Pointer. + +// BAD: should be "leaking param: p to result ~r1 level=0$" +func valuePointer(p *int) unsafe.Pointer { // ERROR "leaking param: p$" + return unsafe.Pointer(reflect.ValueOf(p).Pointer()) // ERROR "p escapes to heap" +} + +// BAD: should be "leaking param: p to result ~r1 level=0$" +func valueUnsafeAddr(p *int) unsafe.Pointer { // ERROR "leaking param: p$" + return unsafe.Pointer(reflect.ValueOf(p).Elem().UnsafeAddr()) // ERROR "p escapes to heap" +} + +// (6) Conversion of a reflect.SliceHeader or reflect.StringHeader +// Data field to or from Pointer. + +func fromSliceData(s []int) unsafe.Pointer { // ERROR "leaking param: s to result ~r1 level=0$" + return unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data) +} + +func fromStringData(s string) unsafe.Pointer { // ERROR "leaking param: s to result ~r1 level=0$" + return unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data) +} + +func toSliceData(s *[]int, p unsafe.Pointer) { // ERROR "s does not escape" "leaking param: p$" + (*reflect.SliceHeader)(unsafe.Pointer(s)).Data = uintptr(p) +} + +func toStringData(s *string, p unsafe.Pointer) { // ERROR "s does not escape" "leaking param: p$" + (*reflect.SliceHeader)(unsafe.Pointer(s)).Data = uintptr(p) +} diff --git a/test/fixedbugs/bug073.go b/test/fixedbugs/bug073.go index 49b47ae4..f3605b37 100644 --- a/test/fixedbugs/bug073.go +++ b/test/fixedbugs/bug073.go @@ -1,4 +1,4 @@ -// errorcheck +// compile // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -7,8 +7,8 @@ package main func main() { - var s int = 0; - var x int = 0; - x = x << s; // ERROR "illegal|inval|shift" - x = x >> s; // ERROR "illegal|inval|shift" + var s int = 0 + var x int = 0 + x = x << s // as of 1.13, these are ok + x = x >> s // as of 1.13, these are ok } diff --git a/test/fixedbugs/bug297.go b/test/fixedbugs/bug297.go index 852d2082..c2bd253d 100644 --- a/test/fixedbugs/bug297.go +++ b/test/fixedbugs/bug297.go @@ -11,5 +11,5 @@ package main type ByteSize float64 const ( _ = iota; // ignore first value by assigning to blank identifier - KB ByteSize = 1<<(10*X) // ERROR "undefined" "is not a constant|as type ByteSize" + KB ByteSize = 1<<(10*X) // ERROR "undefined" ) diff --git a/test/fixedbugs/bug369.dir/main.go b/test/fixedbugs/bug369.dir/main.go index 4812602c..03b53a5b 100644 --- a/test/fixedbugs/bug369.dir/main.go +++ b/test/fixedbugs/bug369.dir/main.go @@ -29,6 +29,7 @@ func BenchmarkSlowNonASCII(b *testing.B) { } func main() { + testing.Init() os.Args = []string{os.Args[0], "-test.benchtime=100ms"} flag.Parse() diff --git a/test/fixedbugs/gcc89321.go b/test/fixedbugs/gcc89321.go new file mode 100644 index 00000000..93ca6b40 --- /dev/null +++ b/test/fixedbugs/gcc89321.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2019 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. + +// https://gcc.gnu.org/PR89321 +// gccgo compiler crash building map literals with a zero-sized value type. + +package p + +type M map[byte]struct{} + +var ( + M1 = M{1: {}, 2: {}, 3: {}} + M2 = M{1: {}, 2: {}} +) diff --git a/test/fixedbugs/issue11361.go b/test/fixedbugs/issue11361.go index d01776b4..1260ea89 100644 --- a/test/fixedbugs/issue11361.go +++ b/test/fixedbugs/issue11361.go @@ -8,4 +8,4 @@ package a import "fmt" // ERROR "imported and not used" -const n = fmt // ERROR "fmt without selector" "fmt is not a constant" +const n = fmt // ERROR "fmt without selector" diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go index 9d81a043..adbbb28b 100644 --- a/test/fixedbugs/issue12006.go +++ b/test/fixedbugs/issue12006.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l +// errorcheck -0 -m -l -newescape=true // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -23,7 +23,7 @@ func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking var sink []*int -func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" "leaking param content: vals" +func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" vals = append(vals, x) sink = vals return FooN(vals...) @@ -37,28 +37,28 @@ func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals" func TFooN() { for i := 0; i < 1000; i++ { var i, j int - FooN(&i, &j) // ERROR "TFooN &i does not escape" "TFooN &j does not escape" "TFooN ... argument does not escape" + FooN(&i, &j) // ERROR "TFooN ... argument does not escape" } } func TFooNx() { for i := 0; i < 1000; i++ { var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" - FooNx(&k, &i, &j) // ERROR "&k escapes to heap" "&i escapes to heap" "&j escapes to heap" "TFooNx ... argument does not escape" + FooNx(&k, &i, &j) // ERROR "TFooNx ... argument does not escape" } } func TFooNy() { for i := 0; i < 1000; i++ { var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" - FooNy(&k, &i, &j) // ERROR "&i escapes to heap" "&j escapes to heap" "&k escapes to heap" "... argument escapes to heap" + FooNy(&k, &i, &j) // ERROR "... argument escapes to heap" } } func TFooNz() { for i := 0; i < 1000; i++ { var i, j int // ERROR "moved to heap: i" "moved to heap: j" - FooNz(&i, &j) // ERROR "&i escapes to heap" "&j escapes to heap" "... argument escapes to heap" + FooNz(&i, &j) // ERROR "... argument escapes to heap" } } @@ -83,7 +83,7 @@ func FooI(args ...interface{}) { // ERROR "leaking param content: args" func TFooI() { a := int32(1) // ERROR "moved to heap: a" b := "cat" - c := &a // ERROR "&a escapes to heap" + c := &a FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooI ... argument does not escape" } @@ -107,14 +107,14 @@ func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result func TFooJ1() { a := int32(1) b := "cat" - c := &a // ERROR "TFooJ1 &a does not escape" + c := &a FooJ(a, b, c) // ERROR "TFooJ1 a does not escape" "TFooJ1 b does not escape" "TFooJ1 c does not escape" "TFooJ1 ... argument does not escape" } func TFooJ2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" - c := &a // ERROR "&a escapes to heap" + c := &a isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooJ2 ... argument does not escape" } @@ -143,7 +143,7 @@ func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r1 l func TFooK2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" - c := &a // ERROR "&a escapes to heap" + c := &a fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooK2 &\[4\]interface {} literal does not escape" isink = FooK(fs) } @@ -168,7 +168,7 @@ func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~ func TFooL2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" - c := &a // ERROR "&a escapes to heap" + c := &a s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooL2 \[\]interface {} literal does not escape" isink = FooL(s) } diff --git a/test/fixedbugs/issue12588.go b/test/fixedbugs/issue12588.go index 87f1d478..f99807b9 100644 --- a/test/fixedbugs/issue12588.go +++ b/test/fixedbugs/issue12588.go @@ -18,7 +18,7 @@ type B struct { } func f(a A) int { - for i, x := range &a.b { // ERROR "f &a.b does not escape" + for i, x := range &a.b { if x != 0 { return 64*i + int(x) } @@ -27,7 +27,7 @@ func f(a A) int { } func g(a *A) int { // ERROR "g a does not escape" - for i, x := range &a.b { // ERROR "g &a.b does not escape" + for i, x := range &a.b { if x != 0 { return 64*i + int(x) } @@ -36,7 +36,7 @@ func g(a *A) int { // ERROR "g a does not escape" } func h(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" - for i, x := range &a.b { // ERROR "h &a.b does not escape" + for i, x := range &a.b { if i == 0 { return x } @@ -45,7 +45,7 @@ func h(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" } func h2(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" - p := &a.b // ERROR "h2 &a.b does not escape" + p := &a.b for i, x := range p { if i == 0 { return x @@ -56,7 +56,7 @@ func h2(a *B) *uint64 { // ERROR "leaking param: a to result ~r1 level=1" // Seems like below should be level=1, not 0. func k(a B) *uint64 { // ERROR "leaking param: a to result ~r1 level=0" - for i, x := range &a.b { // ERROR "k &a.b does not escape" + for i, x := range &a.b { if i == 0 { return x } @@ -70,16 +70,16 @@ func main() { var a1, a2 A var b1, b2, b3, b4 B var x1, x2, x3, x4 uint64 // ERROR "moved to heap: x1" "moved to heap: x3" - b1.b[0] = &x1 // ERROR "&x1 escapes to heap" - b2.b[0] = &x2 // ERROR "main &x2 does not escape" - b3.b[0] = &x3 // ERROR "&x3 escapes to heap" - b4.b[0] = &x4 // ERROR "main &x4 does not escape" + b1.b[0] = &x1 + b2.b[0] = &x2 + b3.b[0] = &x3 + b4.b[0] = &x4 f(a1) - g(&a2) // ERROR "main &a2 does not escape" - sink = h(&b1) // ERROR "main &b1 does not escape" - h(&b2) // ERROR "main &b2 does not escape" - sink = h2(&b1) // ERROR "main &b1 does not escape" - h2(&b4) // ERROR "main &b4 does not escape" + g(&a2) + sink = h(&b1) + h(&b2) + sink = h2(&b1) + h2(&b4) x1 = 17 println("*sink=", *sink) // Verify that sink addresses x1 x3 = 42 diff --git a/test/fixedbugs/issue13799.go b/test/fixedbugs/issue13799.go index 4819b5af..b9bf49ca 100644 --- a/test/fixedbugs/issue13799.go +++ b/test/fixedbugs/issue13799.go @@ -50,10 +50,10 @@ func test1(iter int) { // var fn func() // this makes it work, because fn stays off heap j := 0 // ERROR "moved to heap: j$" fn = func() { // ERROR "func literal escapes to heap$" - m[i] = append(m[i], 0) // ERROR "&i escapes to heap$" - if j < 25 { // ERROR "&j escapes to heap$" + m[i] = append(m[i], 0) + if j < 25 { j++ - fn() // ERROR "&fn escapes to heap$" + fn() } } fn() @@ -92,16 +92,16 @@ func test3(iter int) { const maxI = 500 var x int // ERROR "moved to heap: x$" - m := &x // ERROR "&x escapes to heap$" + m := &x var fn func() // ERROR "moved to heap: fn$" for i := 0; i < maxI; i++ { // var fn func() // this makes it work, because fn stays off heap j := 0 // ERROR "moved to heap: j$" fn = func() { // ERROR "func literal escapes to heap$" - if j < 100 { // ERROR "&j escapes to heap$" + if j < 100 { j++ - fn() // ERROR "&fn escapes to heap$" + fn() } else { *m = *m + 1 } @@ -118,7 +118,7 @@ func test4(iter int) { const maxI = 500 var x int - m := &x // ERROR "test4 &x does not escape$" + m := &x // var fn func() for i := 0; i < maxI; i++ { @@ -157,7 +157,7 @@ func test5(iter int) { const maxI = 500 var x int // ERROR "moved to heap: x$" - m := &x // ERROR "&x escapes to heap$" + m := &x var fn *str for i := 0; i < maxI; i++ { @@ -175,7 +175,7 @@ func test6(iter int) { const maxI = 500 var x int - m := &x // ERROR "&x does not escape$" + m := &x // var fn *str for i := 0; i < maxI; i++ { diff --git a/test/fixedbugs/issue15002.go b/test/fixedbugs/issue15002.go index a27fd923..936105ed 100644 --- a/test/fixedbugs/issue15002.go +++ b/test/fixedbugs/issue15002.go @@ -48,7 +48,7 @@ func test16(x []byte) uint16 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() @@ -66,7 +66,7 @@ func test16i(x []byte, i int) uint16 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() @@ -80,7 +80,7 @@ func test32(x []byte) uint32 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() @@ -94,7 +94,7 @@ func test32i(x []byte, i int) uint32 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() @@ -108,7 +108,7 @@ func test64(x []byte) uint64 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() @@ -123,7 +123,7 @@ func test64i(x []byte, i int) uint64 { panic("no fault or bounds check failure happened") } s := fmt.Sprintf("%s", r) - if s != "runtime error: index out of range" { + if s != "runtime error: index out of range [1] with length 1" { panic("bad panic: " + s) } }() diff --git a/test/fixedbugs/issue15071.dir/exp/exp.go b/test/fixedbugs/issue15071.dir/exp.go index e6041e60..e6041e60 100644 --- a/test/fixedbugs/issue15071.dir/exp/exp.go +++ b/test/fixedbugs/issue15071.dir/exp.go diff --git a/test/fixedbugs/issue15071.go b/test/fixedbugs/issue15071.go new file mode 100644 index 00000000..af6f1341 --- /dev/null +++ b/test/fixedbugs/issue15071.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue15609.go b/test/fixedbugs/issue15609.go new file mode 100644 index 00000000..e0bf8a42 --- /dev/null +++ b/test/fixedbugs/issue15609.go @@ -0,0 +1,9 @@ +// runindir + +// +build !nacl + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue15992.go b/test/fixedbugs/issue15992.go new file mode 100644 index 00000000..957bb89f --- /dev/null +++ b/test/fixedbugs/issue15992.go @@ -0,0 +1,38 @@ +// run + +// Copyright 2018 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. + +package main + +import ( + "fmt" +) + +func f(a []byte) ([]byte, []byte) { + return a, []byte("abc") +} + +func g(a []byte) ([]byte, string) { + return a, "abc" +} + +func h(m map[int]int) (map[int]int, int) { + return m, 0 +} + +func main() { + a := []byte{1, 2, 3} + n := copy(f(a)) + fmt.Println(n, a) + + b := []byte{1, 2, 3} + n = copy(f(b)) + fmt.Println(n, b) + + m := map[int]int{0: 0} + fmt.Println(len(m)) + delete(h(m)) + fmt.Println(len(m)) +} diff --git a/test/fixedbugs/issue15992.out b/test/fixedbugs/issue15992.out new file mode 100644 index 00000000..e0011e3e --- /dev/null +++ b/test/fixedbugs/issue15992.out @@ -0,0 +1,4 @@ +3 [97 98 99] +3 [97 98 99] +1 +0 diff --git a/test/fixedbugs/issue17038.go b/test/fixedbugs/issue17038.go index e07a4b22..4d7422c6 100644 --- a/test/fixedbugs/issue17038.go +++ b/test/fixedbugs/issue17038.go @@ -6,4 +6,4 @@ package main -const A = complex(0()) // ERROR "cannot call non-function" "const initializer .* is not a constant" +const A = complex(0()) // ERROR "cannot call non-function" "not enough arguments" diff --git a/test/fixedbugs/issue17318.go b/test/fixedbugs/issue17318.go index fe00859b..f8755175 100644 --- a/test/fixedbugs/issue17318.go +++ b/test/fixedbugs/issue17318.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l +// errorcheck -0 -N -m -l -newescape=true // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -26,8 +26,8 @@ func (e ent) String() string { } //go:noinline -func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$" - enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$" +func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "foo ops does not escape" + enqueue := func(i int) fmt.Stringer { // ERROR "foo func literal does not escape" return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" } err = enqueue(4) @@ -39,7 +39,7 @@ func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" func main() { // 3 identical functions, to get different escape behavior. - f := func(i, j int) ent { // ERROR "func literal escapes to heap$" + f := func(i, j int) ent { // ERROR "main func literal does not escape" return ent(i + j) } i := foo(f, 3).(ent) diff --git a/test/fixedbugs/issue19113.go b/test/fixedbugs/issue19113.go new file mode 100644 index 00000000..5e01dde6 --- /dev/null +++ b/test/fixedbugs/issue19113.go @@ -0,0 +1,108 @@ +// run + +// Copyright 2019 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. + +package main + +import "reflect" + +var tests = []interface{}{ + func(x int, s int) int { + return x << s + }, + func(x int, s int64) int { + return x << s + }, + func(x int, s int32) int { + return x << s + }, + func(x int, s int16) int { + return x << s + }, + func(x int, s int8) int { + return x << s + }, + func(x int, s int) int { + return x >> s + }, + func(x int, s int64) int { + return x >> s + }, + func(x int, s int32) int { + return x >> s + }, + func(x int, s int16) int { + return x >> s + }, + func(x int, s int8) int { + return x >> s + }, + func(x uint, s int) uint { + return x << s + }, + func(x uint, s int64) uint { + return x << s + }, + func(x uint, s int32) uint { + return x << s + }, + func(x uint, s int16) uint { + return x << s + }, + func(x uint, s int8) uint { + return x << s + }, + func(x uint, s int) uint { + return x >> s + }, + func(x uint, s int64) uint { + return x >> s + }, + func(x uint, s int32) uint { + return x >> s + }, + func(x uint, s int16) uint { + return x >> s + }, + func(x uint, s int8) uint { + return x >> s + }, +} + +func main() { + for _, t := range tests { + runTest(reflect.ValueOf(t)) + } +} + +func runTest(f reflect.Value) { + xt := f.Type().In(0) + st := f.Type().In(1) + + for _, x := range []int{1, 0, -1} { + for _, s := range []int{-99, -64, -63, -32, -31, -16, -15, -8, -7, -1, 0, 1, 7, 8, 15, 16, 31, 32, 63, 64, 99} { + args := []reflect.Value{ + reflect.ValueOf(x).Convert(xt), + reflect.ValueOf(s).Convert(st), + } + if s < 0 { + shouldPanic(func() { + f.Call(args) + }) + } else { + f.Call(args) // should not panic + } + } + } +} + +func shouldPanic(f func()) { + defer func() { + if recover() == nil { + panic("did not panic") + } + }() + f() +} diff --git a/test/fixedbugs/issue19743.go b/test/fixedbugs/issue19743.go index e57b19c8..5089cc61 100644 --- a/test/fixedbugs/issue19743.go +++ b/test/fixedbugs/issue19743.go @@ -22,8 +22,8 @@ func toString(b immutableBytes) string { // ERROR "leaking param: b$" return s } - strHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) // ERROR "toString &s does not escape$" - strHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data // ERROR "toString &b does not escape$" + strHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) + strHeader.Data = (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data l := len(b) strHeader.Len = l diff --git a/test/fixedbugs/issue21709.go b/test/fixedbugs/issue21709.go index bf5d9d23..6e7f1d5b 100644 --- a/test/fixedbugs/issue21709.go +++ b/test/fixedbugs/issue21709.go @@ -17,7 +17,7 @@ func F1() { var s S // ERROR "moved to heap: s" for i := 0; i < N; i++ { fs := []func(){ // ERROR "F1 \[\]func\(\) literal does not escape" - s.Inc, // ERROR "F1 s.Inc does not escape" "s escapes to heap" + s.Inc, // ERROR "F1 s.Inc does not escape" } for _, f := range fs { f() @@ -29,7 +29,7 @@ func F2() { var s S // ERROR "moved to heap: s" for i := 0; i < N; i++ { for _, f := range []func(){ // ERROR "F2 \[\]func\(\) literal does not escape" - s.Inc, // ERROR "F2 s.Inc does not escape" "s escapes to heap" + s.Inc, // ERROR "F2 s.Inc does not escape" } { f() } diff --git a/test/fixedbugs/issue22326.go b/test/fixedbugs/issue22326.go new file mode 100644 index 00000000..a675655b --- /dev/null +++ b/test/fixedbugs/issue22326.go @@ -0,0 +1,25 @@ +// run + +// Copyright 2019 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. + +package main + +var ( + _ = d + _ = f("_", c, b) + a = f("a") + b = f("b") + c = f("c") + d = f("d") +) + +func f(s string, rest ...int) int { + print(s) + return 0 +} + +func main() { + println() +} diff --git a/test/fixedbugs/issue22326.out b/test/fixedbugs/issue22326.out new file mode 100644 index 00000000..f0204389 --- /dev/null +++ b/test/fixedbugs/issue22326.out @@ -0,0 +1 @@ +abc_d diff --git a/test/fixedbugs/issue23823.go b/test/fixedbugs/issue23823.go index 9297966c..2f802d09 100644 --- a/test/fixedbugs/issue23823.go +++ b/test/fixedbugs/issue23823.go @@ -1,4 +1,4 @@ -// compile +// errorcheck // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -6,14 +6,10 @@ package p -// The compiler cannot handle this. Disabled for now. -// See issue #25838. -/* type I1 = interface { I2 } -type I2 interface { +type I2 interface { // ERROR "invalid recursive type" I1 } -*/ diff --git a/test/fixedbugs/issue25897a.go b/test/fixedbugs/issue25897a.go new file mode 100644 index 00000000..6a724a79 --- /dev/null +++ b/test/fixedbugs/issue25897a.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2019 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. + +// Make sure the runtime can scan args of an unstarted goroutine +// which starts with a reflect-generated function. + +package main + +import ( + "reflect" + "runtime" +) + +const N = 100 + +func main() { + runtime.GOMAXPROCS(1) + c := make(chan bool, N) + for i := 0; i < N; i++ { + f := reflect.MakeFunc(reflect.TypeOf(((func(*int))(nil))), + func(args []reflect.Value) []reflect.Value { + c <- true + return nil + }).Interface().(func(*int)) + go f(nil) + } + runtime.GC() + for i := 0; i < N; i++ { + <-c + } +} diff --git a/test/fixedbugs/issue25897b.go b/test/fixedbugs/issue25897b.go new file mode 100644 index 00000000..09a9673a --- /dev/null +++ b/test/fixedbugs/issue25897b.go @@ -0,0 +1,38 @@ +// run + +// Copyright 2019 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. + +// Make sure the runtime can scan args of an unstarted goroutine +// which starts with a reflect-generated function. + +package main + +import ( + "reflect" + "runtime" +) + +const N = 100 + +type T struct { +} + +func (t *T) Foo(c chan bool) { + c <- true +} + +func main() { + t := &T{} + runtime.GOMAXPROCS(1) + c := make(chan bool, N) + for i := 0; i < N; i++ { + f := reflect.ValueOf(t).MethodByName("Foo").Interface().(func(chan bool)) + go f(c) + } + runtime.GC() + for i := 0; i < N; i++ { + <-c + } +} diff --git a/test/fixedbugs/issue27732a.go b/test/fixedbugs/issue27732a.go new file mode 100644 index 00000000..41b62a6d --- /dev/null +++ b/test/fixedbugs/issue27732a.go @@ -0,0 +1,23 @@ +// errorcheck -0 -m -l -smallframes -newescape=true + +// Copyright 2019 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. + +// This checks that the -smallframes flag forces a large variable to heap. + +package main + +const ( + bufferLen = 200000 +) + +type kbyte []byte +type circularBuffer [bufferLen]kbyte + +var sink byte + +func main() { + var c circularBuffer // ERROR "moved to heap: c$" + sink = c[0][0] +} diff --git a/test/fixedbugs/issue28085.go b/test/fixedbugs/issue28085.go new file mode 100644 index 00000000..01fffd52 --- /dev/null +++ b/test/fixedbugs/issue28085.go @@ -0,0 +1,29 @@ +// errorcheck + +// Copyright 2018 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. + +package p + +var _ = map[interface{}]int{ + 0: 0, + 0: 0, // ERROR "duplicate" +} + +var _ = map[interface{}]int{ + interface{}(0): 0, + interface{}(0): 0, // ok +} + +func _() { + switch interface{}(0) { + case 0: + case 0: // ERROR "duplicate" + } + + switch interface{}(0) { + case interface{}(0): + case interface{}(0): // ok + } +} diff --git a/test/fixedbugs/issue28748.go b/test/fixedbugs/issue28748.go new file mode 100644 index 00000000..4f9b0222 --- /dev/null +++ b/test/fixedbugs/issue28748.go @@ -0,0 +1,32 @@ +// run + +package main + +import ( + "fmt" + "reflect" + "strings" +) + +// Copyright 2019 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. + +func main() { + defer func() { + e := recover() + if e == nil { + panic("should have panicked") + } + text := fmt.Sprintf("%s", e) // handles both string and runtime.errorString + if !strings.HasPrefix(text, "reflect:") { + panic("wanted a reflect error, got this instead:\n" + text) + } + }() + r := reflect.MakeFunc(reflect.TypeOf(func() error { return nil }), + func(args []reflect.Value) []reflect.Value { + var x [1]reflect.Value + return x[:] + }).Interface().(func() error) + r() +} diff --git a/test/fixedbugs/issue28926.go b/test/fixedbugs/issue28926.go new file mode 100644 index 00000000..5a46bd30 --- /dev/null +++ b/test/fixedbugs/issue28926.go @@ -0,0 +1,24 @@ +// errorcheck + +// Copyright 2018 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. + +package main + +type Stringer interface { + String() string +} + +func main() { + var e interface{} + switch e := e.(type) { + case G: // ERROR "undefined: G" + e.M() // ok: this error should be ignored because the case failed its typecheck + case E: // ERROR "undefined: E" + e.D() // ok: this error should be ignored because the case failed its typecheck + case Stringer: + // ok: this error should not be ignored to prove that passing legs aren't left out + _ = e.(T) // ERROR "undefined: T" + } +} diff --git a/test/fixedbugs/issue29218.go b/test/fixedbugs/issue29218.go new file mode 100644 index 00000000..ac9fed75 --- /dev/null +++ b/test/fixedbugs/issue29218.go @@ -0,0 +1,24 @@ +// compile + +// Copyright 2019 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. + +package p + +type T struct { + b bool + string +} + +func f() { + var b bool + var t T + for { + switch &t.b { + case &b: + if b { + } + } + } +} diff --git a/test/fixedbugs/issue29504.go b/test/fixedbugs/issue29504.go new file mode 100644 index 00000000..e311f84e --- /dev/null +++ b/test/fixedbugs/issue29504.go @@ -0,0 +1,147 @@ +// run + +// Copyright 2019 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. + +// Make sure that in code involving indexing, the bounds +// check always fails at the line number of the '[' token. + +package main + +import ( + "fmt" + "runtime" + "strings" +) + +type T struct{ a, b, c, d, e int } // unSSAable + +func main() { + shouldPanic(func() { + var a [1]int + sink = a /*line :999999:1*/ [ /*line :100:1*/ i] + }) + shouldPanic(func() { + var a [3]int + sink = a /*line :999999:1*/ [ /*line :200:1*/ i] + }) + shouldPanic(func() { + var a []int + sink = a /*line :999999:1*/ [ /*line :300:1*/ i] + }) + shouldPanic(func() { + var a [1]int + a /*line :999999:1*/ [ /*line :400:1*/ i] = 1 + }) + shouldPanic(func() { + var a [3]int + a /*line :999999:1*/ [ /*line :500:1*/ i] = 1 + }) + shouldPanic(func() { + var a []int + a /*line :999999:1*/ [ /*line :600:1*/ i] = 1 + }) + + shouldPanic(func() { + var a [3]T + sinkT = a /*line :999999:1*/ [ /*line :700:1*/ i] + }) + shouldPanic(func() { + var a []T + sinkT = a /*line :999999:1*/ [ /*line :800:1*/ i] + }) + shouldPanic(func() { + var a [3]T + a /*line :999999:1*/ [ /*line :900:1*/ i] = T{} + }) + shouldPanic(func() { + var a []T + a /*line :999999:1*/ [ /*line :1000:1*/ i] = T{} + }) + + shouldPanic(func() { + var a [3]int + sinkS = a /*line :999999:1*/ [ /*line :1100:1*/ i:] + }) + shouldPanic(func() { + var a []int + sinkS = a /*line :999999:1*/ [ /*line :1200:1*/ i:] + }) + shouldPanic(func() { + var a [3]int + sinkS = a /*line :999999:1*/ [: /*line :1300:1*/ i] + }) + shouldPanic(func() { + var a []int + sinkS = a /*line :999999:1*/ [: /*line :1400:1*/ i] + }) + + shouldPanic(func() { + var a [3]T + sinkST = a /*line :999999:1*/ [ /*line :1500:1*/ i:] + }) + shouldPanic(func() { + var a []T + sinkST = a /*line :999999:1*/ [ /*line :1600:1*/ i:] + }) + shouldPanic(func() { + var a [3]T + sinkST = a /*line :999999:1*/ [: /*line :1700:1*/ i] + }) + shouldPanic(func() { + var a []T + sinkST = a /*line :999999:1*/ [: /*line :1800:1*/ i] + }) + + shouldPanic(func() { + s := "foo" + sinkB = s /*line :999999:1*/ [ /*line :1900:1*/ i] + }) + shouldPanic(func() { + s := "foo" + sinkStr = s /*line :999999:1*/ [ /*line :2000:1*/ i:] + }) + shouldPanic(func() { + s := "foo" + sinkStr = s /*line :999999:1*/ [: /*line :2100:1*/ i] + }) + + if bad { + panic("ERRORS") + } +} + +var i = 9 +var sink int +var sinkS []int +var sinkT T +var sinkST []T +var sinkB byte +var sinkStr string + +var bad = false + +func shouldPanic(f func()) { + defer func() { + if recover() == nil { + panic("did not panic") + } + var pcs [10]uintptr + n := runtime.Callers(1, pcs[:]) + iter := runtime.CallersFrames(pcs[:n]) + buf := "" + for { + frame, more := iter.Next() + buf += fmt.Sprintf("%s:%d %s\n", frame.File, frame.Line, frame.Function) + if !more { + break + } + } + if !strings.Contains(buf, "999999") { + fmt.Printf("could not find marker line in traceback:\n%s\n", buf) + bad = true + } + }() + f() +} diff --git a/test/fixedbugs/issue29612.dir/main.go b/test/fixedbugs/issue29612.dir/main.go new file mode 100644 index 00000000..9dbc4c4c --- /dev/null +++ b/test/fixedbugs/issue29612.dir/main.go @@ -0,0 +1,24 @@ +// run + +// Copyright 2019 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. + +// Do not panic on conversion to anonymous interface, which +// is similar-looking interface types in different packages. + +package main + +import ( + ssa1 "./p1/ssa" + ssa2 "./p2/ssa" +) + +func main() { + v1 := &ssa1.T{} + _ = v1 + + v2 := &ssa2.T{} + ssa2.Works(v2) + ssa2.Panics(v2) // This call must not panic +} diff --git a/test/fixedbugs/issue29612.dir/p1/ssa/ssa.go b/test/fixedbugs/issue29612.dir/p1/ssa/ssa.go new file mode 100644 index 00000000..8f6eb97f --- /dev/null +++ b/test/fixedbugs/issue29612.dir/p1/ssa/ssa.go @@ -0,0 +1,18 @@ +// Copyright 2019 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. + +package ssa + +type T struct{} + +func (T) foo() {} + +type fooer interface { + foo() +} + +func Unused(v interface{}) { + v.(fooer).foo() + v.(interface{ foo() }).foo() +} diff --git a/test/fixedbugs/issue29612.dir/p2/ssa/ssa.go b/test/fixedbugs/issue29612.dir/p2/ssa/ssa.go new file mode 100644 index 00000000..df57314b --- /dev/null +++ b/test/fixedbugs/issue29612.dir/p2/ssa/ssa.go @@ -0,0 +1,28 @@ +// Copyright 2019 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. + +package ssa + +type T struct{} + +func (T) foo() {} + +type fooer interface { + foo() +} + +func Works(v interface{}) { + switch v.(type) { + case interface{}: + v.(fooer).foo() + } +} + +func Panics(v interface{}) { + switch v.(type) { + case interface{}: + v.(fooer).foo() + v.(interface{ foo() }).foo() + } +} diff --git a/test/fixedbugs/issue29612.go b/test/fixedbugs/issue29612.go new file mode 100644 index 00000000..87c96b48 --- /dev/null +++ b/test/fixedbugs/issue29612.go @@ -0,0 +1,7 @@ +// runindir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue29855.go b/test/fixedbugs/issue29855.go new file mode 100644 index 00000000..b57eae2b --- /dev/null +++ b/test/fixedbugs/issue29855.go @@ -0,0 +1,17 @@ +// errorcheck + +// Copyright 2018 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. + +package main + +type T struct { + GlobalName string +} + +var t = T{Name: "foo"} // ERROR "unknown field 'Name' in struct literal of type T" + +func (t T) Name() string { + return t.GlobalName +} diff --git a/test/fixedbugs/issue29919.dir/a.go b/test/fixedbugs/issue29919.dir/a.go index cfccc4aa..078f973b 100644 --- a/test/fixedbugs/issue29919.dir/a.go +++ b/test/fixedbugs/issue29919.dir/a.go @@ -34,8 +34,8 @@ func f() int { if !strings.Contains(s, "a.go:19") { panic("missing a.go:19") } - if !strings.Contains(s, "a.init.ializers") { - panic("missing a.init.ializers") + if !strings.Contains(s, "a.init") { + panic("missing a.init") } // Check the CallersFrames results. @@ -58,15 +58,15 @@ func f() int { panic("traceback truncated after f") } f, more = iter.Next() - if f.Function != "a.init.ializers" || !strings.HasSuffix(f.File, "a.go") || f.Line != 15 { - panic(fmt.Sprintf("bad init.ializers %v\n", f)) + if f.Function != "a.init" || !strings.HasSuffix(f.File, "a.go") || f.Line != 15 { + panic(fmt.Sprintf("bad init %v\n", f)) } if !more { - panic("traceback truncated after init.ializers") + panic("traceback truncated after init") } f, _ = iter.Next() - if f.Function != "runtime.main" { - panic("runtime.main missing") + if !strings.HasPrefix(f.Function, "runtime.") { + panic("runtime. driver missing") } return 0 diff --git a/test/fixedbugs/issue30085.go b/test/fixedbugs/issue30085.go new file mode 100644 index 00000000..8223c855 --- /dev/null +++ b/test/fixedbugs/issue30085.go @@ -0,0 +1,12 @@ +// errorcheck + +// Copyright 2019 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. + +package main + +func main() { + var c, d = 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values" + var e, f, g = 1, 2 // ERROR "assignment mismatch: 3 variables but 2 values" +} diff --git a/test/fixedbugs/issue30087.go b/test/fixedbugs/issue30087.go new file mode 100644 index 00000000..dc12364d --- /dev/null +++ b/test/fixedbugs/issue30087.go @@ -0,0 +1,14 @@ +// errorcheck + +// Copyright 2019 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. + +package main + +func main() { + var a, b = 1 // ERROR "assignment mismatch: 2 variables but 1 values" + _ = 1, 2 // ERROR "assignment mismatch: 1 variables but 2 values" + c, d := 1 // ERROR "assignment mismatch: 2 variables but 1 values" + e, f := 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values" +} diff --git a/test/fixedbugs/issue30116.go b/test/fixedbugs/issue30116.go new file mode 100644 index 00000000..452a6e3a --- /dev/null +++ b/test/fixedbugs/issue30116.go @@ -0,0 +1,112 @@ +// run + +// Copyright 2019 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. + +// This test makes sure the text output for bounds check failures is as expected. + +package main + +import ( + "fmt" + "os" + "runtime" + "text/tabwriter" +) + +// Testing with length 3 slices, arrays, and strings. +// Large (>1<<32) values are included to test 32-bit platforms. +var indexes = []int64{-9876543210, -1, 0, 2, 3, 9876543210} +var slices = []int64{-9876543210, -1, 0, 3, 4, 9876543210} + +var w *tabwriter.Writer + +func main() { + w = tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight) + defer w.Flush() + doIndex() + doSlice() + doSlice3() +} +func doIndex() { + a := []int{1, 2, 3} + for _, i := range indexes { + printPanic(fmt.Sprintf("slice[%d]", i), func() { + _ = a[i] + }) + } + b := [3]int{1, 2, 3} + for _, i := range indexes { + printPanic(fmt.Sprintf("array[%d]", i), func() { + _ = b[i] + }) + } + c := "123" + for _, i := range indexes { + printPanic(fmt.Sprintf("string[%d]", i), func() { + _ = c[i] + }) + } +} + +func doSlice() { + a := []int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("slice[%d:%d]", i, j), func() { + _ = a[i:j] + }) + } + } + b := [3]int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("array[%d:%d]", i, j), func() { + _ = b[i:j] + }) + } + } + c := "123" + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("string[%d:%d]", i, j), func() { + _ = c[i:j] + }) + } + } +} + +func doSlice3() { + a := []int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + for _, k := range slices { + printPanic(fmt.Sprintf("slice[%d:%d:%d]", i, j, k), func() { + _ = a[i:j:k] + }) + } + } + } + b := [3]int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + for _, k := range slices { + printPanic(fmt.Sprintf("array[%d:%d:%d]", i, j, k), func() { + _ = b[i:j:k] + }) + } + } + } +} + +func printPanic(msg string, f func()) { + defer func() { + res := "no panic" + if e := recover(); e != nil { + res = e.(runtime.Error).Error() + } + fmt.Fprintf(w, "%s\t %s\n", msg, res) + }() + f() +} diff --git a/test/fixedbugs/issue30116.out b/test/fixedbugs/issue30116.out new file mode 100644 index 00000000..bde134d9 --- /dev/null +++ b/test/fixedbugs/issue30116.out @@ -0,0 +1,558 @@ + slice[-9876543210] runtime error: index out of range [-9876543210] + slice[-1] runtime error: index out of range [-1] + slice[0] no panic + slice[2] no panic + slice[3] runtime error: index out of range [3] with length 3 + slice[9876543210] runtime error: index out of range [9876543210] with length 3 + array[-9876543210] runtime error: index out of range [-9876543210] + array[-1] runtime error: index out of range [-1] + array[0] no panic + array[2] no panic + array[3] runtime error: index out of range [3] with length 3 + array[9876543210] runtime error: index out of range [9876543210] with length 3 + string[-9876543210] runtime error: index out of range [-9876543210] + string[-1] runtime error: index out of range [-1] + string[0] no panic + string[2] no panic + string[3] runtime error: index out of range [3] with length 3 + string[9876543210] runtime error: index out of range [9876543210] with length 3 + slice[-9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[-9876543210:-1] runtime error: slice bounds out of range [:-1] + slice[-9876543210:0] runtime error: slice bounds out of range [-9876543210:] + slice[-9876543210:3] runtime error: slice bounds out of range [-9876543210:] + slice[-9876543210:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[-9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + slice[-1:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[-1:-1] runtime error: slice bounds out of range [:-1] + slice[-1:0] runtime error: slice bounds out of range [-1:] + slice[-1:3] runtime error: slice bounds out of range [-1:] + slice[-1:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[-1:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + slice[0:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[0:-1] runtime error: slice bounds out of range [:-1] + slice[0:0] no panic + slice[0:3] no panic + slice[0:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[0:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + slice[3:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[3:-1] runtime error: slice bounds out of range [:-1] + slice[3:0] runtime error: slice bounds out of range [3:0] + slice[3:3] no panic + slice[3:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[3:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + slice[4:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[4:-1] runtime error: slice bounds out of range [:-1] + slice[4:0] runtime error: slice bounds out of range [4:0] + slice[4:3] runtime error: slice bounds out of range [4:3] + slice[4:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[4:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + slice[9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + slice[9876543210:-1] runtime error: slice bounds out of range [:-1] + slice[9876543210:0] runtime error: slice bounds out of range [9876543210:0] + slice[9876543210:3] runtime error: slice bounds out of range [9876543210:3] + slice[9876543210:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with capacity 3 + array[-9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[-9876543210:-1] runtime error: slice bounds out of range [:-1] + array[-9876543210:0] runtime error: slice bounds out of range [-9876543210:] + array[-9876543210:3] runtime error: slice bounds out of range [-9876543210:] + array[-9876543210:4] runtime error: slice bounds out of range [:4] with length 3 + array[-9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + array[-1:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[-1:-1] runtime error: slice bounds out of range [:-1] + array[-1:0] runtime error: slice bounds out of range [-1:] + array[-1:3] runtime error: slice bounds out of range [-1:] + array[-1:4] runtime error: slice bounds out of range [:4] with length 3 + array[-1:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + array[0:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[0:-1] runtime error: slice bounds out of range [:-1] + array[0:0] no panic + array[0:3] no panic + array[0:4] runtime error: slice bounds out of range [:4] with length 3 + array[0:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + array[3:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[3:-1] runtime error: slice bounds out of range [:-1] + array[3:0] runtime error: slice bounds out of range [3:0] + array[3:3] no panic + array[3:4] runtime error: slice bounds out of range [:4] with length 3 + array[3:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + array[4:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[4:-1] runtime error: slice bounds out of range [:-1] + array[4:0] runtime error: slice bounds out of range [4:0] + array[4:3] runtime error: slice bounds out of range [4:3] + array[4:4] runtime error: slice bounds out of range [:4] with length 3 + array[4:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + array[9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + array[9876543210:-1] runtime error: slice bounds out of range [:-1] + array[9876543210:0] runtime error: slice bounds out of range [9876543210:0] + array[9876543210:3] runtime error: slice bounds out of range [9876543210:3] + array[9876543210:4] runtime error: slice bounds out of range [:4] with length 3 + array[9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[-9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[-9876543210:-1] runtime error: slice bounds out of range [:-1] + string[-9876543210:0] runtime error: slice bounds out of range [-9876543210:] + string[-9876543210:3] runtime error: slice bounds out of range [-9876543210:] + string[-9876543210:4] runtime error: slice bounds out of range [:4] with length 3 + string[-9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[-1:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[-1:-1] runtime error: slice bounds out of range [:-1] + string[-1:0] runtime error: slice bounds out of range [-1:] + string[-1:3] runtime error: slice bounds out of range [-1:] + string[-1:4] runtime error: slice bounds out of range [:4] with length 3 + string[-1:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[0:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[0:-1] runtime error: slice bounds out of range [:-1] + string[0:0] no panic + string[0:3] no panic + string[0:4] runtime error: slice bounds out of range [:4] with length 3 + string[0:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[3:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[3:-1] runtime error: slice bounds out of range [:-1] + string[3:0] runtime error: slice bounds out of range [3:0] + string[3:3] no panic + string[3:4] runtime error: slice bounds out of range [:4] with length 3 + string[3:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[4:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[4:-1] runtime error: slice bounds out of range [:-1] + string[4:0] runtime error: slice bounds out of range [4:0] + string[4:3] runtime error: slice bounds out of range [4:3] + string[4:4] runtime error: slice bounds out of range [:4] with length 3 + string[4:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + string[9876543210:-9876543210] runtime error: slice bounds out of range [:-9876543210] + string[9876543210:-1] runtime error: slice bounds out of range [:-1] + string[9876543210:0] runtime error: slice bounds out of range [9876543210:0] + string[9876543210:3] runtime error: slice bounds out of range [9876543210:3] + string[9876543210:4] runtime error: slice bounds out of range [:4] with length 3 + string[9876543210:9876543210] runtime error: slice bounds out of range [:9876543210] with length 3 + slice[-9876543210:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[-9876543210:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[-9876543210:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-9876543210:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:-1:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:-1:0] runtime error: slice bounds out of range [:-1:] + slice[-9876543210:-1:3] runtime error: slice bounds out of range [:-1:] + slice[-9876543210:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-9876543210:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:0:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:0:0] runtime error: slice bounds out of range [-9876543210::] + slice[-9876543210:0:3] runtime error: slice bounds out of range [-9876543210::] + slice[-9876543210:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-9876543210:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:3:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:3:0] runtime error: slice bounds out of range [:3:0] + slice[-9876543210:3:3] runtime error: slice bounds out of range [-9876543210::] + slice[-9876543210:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-9876543210:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:4:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:4:0] runtime error: slice bounds out of range [:4:0] + slice[-9876543210:4:3] runtime error: slice bounds out of range [:4:3] + slice[-9876543210:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-9876543210:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-9876543210:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[-9876543210:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[-9876543210:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[-9876543210:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-9876543210:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[-1:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[-1:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[-1:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:-1:-1] runtime error: slice bounds out of range [::-1] + slice[-1:-1:0] runtime error: slice bounds out of range [:-1:] + slice[-1:-1:3] runtime error: slice bounds out of range [:-1:] + slice[-1:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:0:-1] runtime error: slice bounds out of range [::-1] + slice[-1:0:0] runtime error: slice bounds out of range [-1::] + slice[-1:0:3] runtime error: slice bounds out of range [-1::] + slice[-1:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:3:-1] runtime error: slice bounds out of range [::-1] + slice[-1:3:0] runtime error: slice bounds out of range [:3:0] + slice[-1:3:3] runtime error: slice bounds out of range [-1::] + slice[-1:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:4:-1] runtime error: slice bounds out of range [::-1] + slice[-1:4:0] runtime error: slice bounds out of range [:4:0] + slice[-1:4:3] runtime error: slice bounds out of range [:4:3] + slice[-1:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[-1:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[-1:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[-1:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[-1:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[-1:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[-1:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[0:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[0:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[0:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:-1:-1] runtime error: slice bounds out of range [::-1] + slice[0:-1:0] runtime error: slice bounds out of range [:-1:] + slice[0:-1:3] runtime error: slice bounds out of range [:-1:] + slice[0:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:0:-1] runtime error: slice bounds out of range [::-1] + slice[0:0:0] no panic + slice[0:0:3] no panic + slice[0:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:3:-1] runtime error: slice bounds out of range [::-1] + slice[0:3:0] runtime error: slice bounds out of range [:3:0] + slice[0:3:3] no panic + slice[0:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:4:-1] runtime error: slice bounds out of range [::-1] + slice[0:4:0] runtime error: slice bounds out of range [:4:0] + slice[0:4:3] runtime error: slice bounds out of range [:4:3] + slice[0:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[0:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[0:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[0:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[0:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[0:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[3:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[3:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[3:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:-1:-1] runtime error: slice bounds out of range [::-1] + slice[3:-1:0] runtime error: slice bounds out of range [:-1:] + slice[3:-1:3] runtime error: slice bounds out of range [:-1:] + slice[3:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:0:-1] runtime error: slice bounds out of range [::-1] + slice[3:0:0] runtime error: slice bounds out of range [3:0:] + slice[3:0:3] runtime error: slice bounds out of range [3:0:] + slice[3:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:3:-1] runtime error: slice bounds out of range [::-1] + slice[3:3:0] runtime error: slice bounds out of range [:3:0] + slice[3:3:3] no panic + slice[3:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:4:-1] runtime error: slice bounds out of range [::-1] + slice[3:4:0] runtime error: slice bounds out of range [:4:0] + slice[3:4:3] runtime error: slice bounds out of range [:4:3] + slice[3:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[3:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[3:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[3:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[3:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[3:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[4:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[4:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[4:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:-1:-1] runtime error: slice bounds out of range [::-1] + slice[4:-1:0] runtime error: slice bounds out of range [:-1:] + slice[4:-1:3] runtime error: slice bounds out of range [:-1:] + slice[4:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:0:-1] runtime error: slice bounds out of range [::-1] + slice[4:0:0] runtime error: slice bounds out of range [4:0:] + slice[4:0:3] runtime error: slice bounds out of range [4:0:] + slice[4:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:3:-1] runtime error: slice bounds out of range [::-1] + slice[4:3:0] runtime error: slice bounds out of range [:3:0] + slice[4:3:3] runtime error: slice bounds out of range [4:3:] + slice[4:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:4:-1] runtime error: slice bounds out of range [::-1] + slice[4:4:0] runtime error: slice bounds out of range [:4:0] + slice[4:4:3] runtime error: slice bounds out of range [:4:3] + slice[4:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[4:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[4:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[4:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[4:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[4:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:-9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + slice[9876543210:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + slice[9876543210:-9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:-1:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:-1:0] runtime error: slice bounds out of range [:-1:] + slice[9876543210:-1:3] runtime error: slice bounds out of range [:-1:] + slice[9876543210:-1:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:0:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:0:0] runtime error: slice bounds out of range [9876543210:0:] + slice[9876543210:0:3] runtime error: slice bounds out of range [9876543210:0:] + slice[9876543210:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:0:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:3:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:3:0] runtime error: slice bounds out of range [:3:0] + slice[9876543210:3:3] runtime error: slice bounds out of range [9876543210:3:] + slice[9876543210:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:3:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:4:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:4:0] runtime error: slice bounds out of range [:4:0] + slice[9876543210:4:3] runtime error: slice bounds out of range [:4:3] + slice[9876543210:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:4:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + slice[9876543210:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + slice[9876543210:9876543210:-1] runtime error: slice bounds out of range [::-1] + slice[9876543210:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + slice[9876543210:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + slice[9876543210:9876543210:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[9876543210:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with capacity 3 + array[-9876543210:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[-9876543210:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[-9876543210:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-9876543210:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:-1:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:-1:0] runtime error: slice bounds out of range [:-1:] + array[-9876543210:-1:3] runtime error: slice bounds out of range [:-1:] + array[-9876543210:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-9876543210:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:0:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:0:0] runtime error: slice bounds out of range [-9876543210::] + array[-9876543210:0:3] runtime error: slice bounds out of range [-9876543210::] + array[-9876543210:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-9876543210:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:3:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:3:0] runtime error: slice bounds out of range [:3:0] + array[-9876543210:3:3] runtime error: slice bounds out of range [-9876543210::] + array[-9876543210:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-9876543210:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:4:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:4:0] runtime error: slice bounds out of range [:4:0] + array[-9876543210:4:3] runtime error: slice bounds out of range [:4:3] + array[-9876543210:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-9876543210:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-9876543210:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[-9876543210:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[-9876543210:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[-9876543210:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[-9876543210:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[-1:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[-1:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[-1:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:-1:-1] runtime error: slice bounds out of range [::-1] + array[-1:-1:0] runtime error: slice bounds out of range [:-1:] + array[-1:-1:3] runtime error: slice bounds out of range [:-1:] + array[-1:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:0:-1] runtime error: slice bounds out of range [::-1] + array[-1:0:0] runtime error: slice bounds out of range [-1::] + array[-1:0:3] runtime error: slice bounds out of range [-1::] + array[-1:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:3:-1] runtime error: slice bounds out of range [::-1] + array[-1:3:0] runtime error: slice bounds out of range [:3:0] + array[-1:3:3] runtime error: slice bounds out of range [-1::] + array[-1:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:4:-1] runtime error: slice bounds out of range [::-1] + array[-1:4:0] runtime error: slice bounds out of range [:4:0] + array[-1:4:3] runtime error: slice bounds out of range [:4:3] + array[-1:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[-1:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[-1:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[-1:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[-1:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[-1:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[-1:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[0:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[0:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[0:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:-1:-1] runtime error: slice bounds out of range [::-1] + array[0:-1:0] runtime error: slice bounds out of range [:-1:] + array[0:-1:3] runtime error: slice bounds out of range [:-1:] + array[0:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:0:-1] runtime error: slice bounds out of range [::-1] + array[0:0:0] no panic + array[0:0:3] no panic + array[0:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:3:-1] runtime error: slice bounds out of range [::-1] + array[0:3:0] runtime error: slice bounds out of range [:3:0] + array[0:3:3] no panic + array[0:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:4:-1] runtime error: slice bounds out of range [::-1] + array[0:4:0] runtime error: slice bounds out of range [:4:0] + array[0:4:3] runtime error: slice bounds out of range [:4:3] + array[0:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[0:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[0:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[0:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[0:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[0:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[3:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[3:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[3:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:-1:-1] runtime error: slice bounds out of range [::-1] + array[3:-1:0] runtime error: slice bounds out of range [:-1:] + array[3:-1:3] runtime error: slice bounds out of range [:-1:] + array[3:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:0:-1] runtime error: slice bounds out of range [::-1] + array[3:0:0] runtime error: slice bounds out of range [3:0:] + array[3:0:3] runtime error: slice bounds out of range [3:0:] + array[3:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:3:-1] runtime error: slice bounds out of range [::-1] + array[3:3:0] runtime error: slice bounds out of range [:3:0] + array[3:3:3] no panic + array[3:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:4:-1] runtime error: slice bounds out of range [::-1] + array[3:4:0] runtime error: slice bounds out of range [:4:0] + array[3:4:3] runtime error: slice bounds out of range [:4:3] + array[3:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[3:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[3:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[3:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[3:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[3:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[4:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[4:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[4:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:-1:-1] runtime error: slice bounds out of range [::-1] + array[4:-1:0] runtime error: slice bounds out of range [:-1:] + array[4:-1:3] runtime error: slice bounds out of range [:-1:] + array[4:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:0:-1] runtime error: slice bounds out of range [::-1] + array[4:0:0] runtime error: slice bounds out of range [4:0:] + array[4:0:3] runtime error: slice bounds out of range [4:0:] + array[4:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:3:-1] runtime error: slice bounds out of range [::-1] + array[4:3:0] runtime error: slice bounds out of range [:3:0] + array[4:3:3] runtime error: slice bounds out of range [4:3:] + array[4:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:4:-1] runtime error: slice bounds out of range [::-1] + array[4:4:0] runtime error: slice bounds out of range [:4:0] + array[4:4:3] runtime error: slice bounds out of range [:4:3] + array[4:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[4:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[4:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[4:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[4:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[4:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:-9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:-9876543210:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:-9876543210:0] runtime error: slice bounds out of range [:-9876543210:] + array[9876543210:-9876543210:3] runtime error: slice bounds out of range [:-9876543210:] + array[9876543210:-9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:-9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:-1:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:-1:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:-1:0] runtime error: slice bounds out of range [:-1:] + array[9876543210:-1:3] runtime error: slice bounds out of range [:-1:] + array[9876543210:-1:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:-1:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:0:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:0:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:0:0] runtime error: slice bounds out of range [9876543210:0:] + array[9876543210:0:3] runtime error: slice bounds out of range [9876543210:0:] + array[9876543210:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:0:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:3:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:3:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:3:0] runtime error: slice bounds out of range [:3:0] + array[9876543210:3:3] runtime error: slice bounds out of range [9876543210:3:] + array[9876543210:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:3:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:4:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:4:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:4:0] runtime error: slice bounds out of range [:4:0] + array[9876543210:4:3] runtime error: slice bounds out of range [:4:3] + array[9876543210:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:4:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 + array[9876543210:9876543210:-9876543210] runtime error: slice bounds out of range [::-9876543210] + array[9876543210:9876543210:-1] runtime error: slice bounds out of range [::-1] + array[9876543210:9876543210:0] runtime error: slice bounds out of range [:9876543210:0] + array[9876543210:9876543210:3] runtime error: slice bounds out of range [:9876543210:3] + array[9876543210:9876543210:4] runtime error: slice bounds out of range [::4] with length 3 + array[9876543210:9876543210:9876543210] runtime error: slice bounds out of range [::9876543210] with length 3 diff --git a/test/fixedbugs/issue30116u.go b/test/fixedbugs/issue30116u.go new file mode 100644 index 00000000..7c2aea2c --- /dev/null +++ b/test/fixedbugs/issue30116u.go @@ -0,0 +1,112 @@ +// run + +// Copyright 2019 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. + +// This test makes sure the text output for bounds check failures is as expected. + +package main + +import ( + "fmt" + "os" + "runtime" + "text/tabwriter" +) + +// Testing with length 3 slices, arrays, and strings. +// A large (>1<<32) value is included to test 32-bit platforms. +var indexes = []uint64{0, 2, 3, 1<<32 - 1, 1<<64 - 1} +var slices = []uint64{0, 3, 4, 1<<32 - 1, 1<<64 - 1} + +var w *tabwriter.Writer + +func main() { + w = tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight) + defer w.Flush() + doIndex() + doSlice() + doSlice3() +} +func doIndex() { + a := []int{1, 2, 3} + for _, i := range indexes { + printPanic(fmt.Sprintf("slice[%d]", i), func() { + _ = a[i] + }) + } + b := [3]int{1, 2, 3} + for _, i := range indexes { + printPanic(fmt.Sprintf("array[%d]", i), func() { + _ = b[i] + }) + } + c := "123" + for _, i := range indexes { + printPanic(fmt.Sprintf("string[%d]", i), func() { + _ = c[i] + }) + } +} + +func doSlice() { + a := []int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("slice[%d:%d]", i, j), func() { + _ = a[i:j] + }) + } + } + b := [3]int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("array[%d:%d]", i, j), func() { + _ = b[i:j] + }) + } + } + c := "123" + for _, i := range slices { + for _, j := range slices { + printPanic(fmt.Sprintf("string[%d:%d]", i, j), func() { + _ = c[i:j] + }) + } + } +} + +func doSlice3() { + a := []int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + for _, k := range slices { + printPanic(fmt.Sprintf("slice[%d:%d:%d]", i, j, k), func() { + _ = a[i:j:k] + }) + } + } + } + b := [3]int{1, 2, 3} + for _, i := range slices { + for _, j := range slices { + for _, k := range slices { + printPanic(fmt.Sprintf("array[%d:%d:%d]", i, j, k), func() { + _ = b[i:j:k] + }) + } + } + } +} + +func printPanic(msg string, f func()) { + defer func() { + res := "no panic" + if e := recover(); e != nil { + res = e.(runtime.Error).Error() + } + fmt.Fprintf(w, "%s\t %s\n", msg, res) + }() + f() +} diff --git a/test/fixedbugs/issue30116u.out b/test/fixedbugs/issue30116u.out new file mode 100644 index 00000000..ee19192a --- /dev/null +++ b/test/fixedbugs/issue30116u.out @@ -0,0 +1,340 @@ + slice[0] no panic + slice[2] no panic + slice[3] runtime error: index out of range [3] with length 3 + slice[4294967295] runtime error: index out of range [4294967295] with length 3 + slice[18446744073709551615] runtime error: index out of range [18446744073709551615] with length 3 + array[0] no panic + array[2] no panic + array[3] runtime error: index out of range [3] with length 3 + array[4294967295] runtime error: index out of range [4294967295] with length 3 + array[18446744073709551615] runtime error: index out of range [18446744073709551615] with length 3 + string[0] no panic + string[2] no panic + string[3] runtime error: index out of range [3] with length 3 + string[4294967295] runtime error: index out of range [4294967295] with length 3 + string[18446744073709551615] runtime error: index out of range [18446744073709551615] with length 3 + slice[0:0] no panic + slice[0:3] no panic + slice[0:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[0:4294967295] runtime error: slice bounds out of range [:4294967295] with capacity 3 + slice[0:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with capacity 3 + slice[3:0] runtime error: slice bounds out of range [3:0] + slice[3:3] no panic + slice[3:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[3:4294967295] runtime error: slice bounds out of range [:4294967295] with capacity 3 + slice[3:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with capacity 3 + slice[4:0] runtime error: slice bounds out of range [4:0] + slice[4:3] runtime error: slice bounds out of range [4:3] + slice[4:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[4:4294967295] runtime error: slice bounds out of range [:4294967295] with capacity 3 + slice[4:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with capacity 3 + slice[4294967295:0] runtime error: slice bounds out of range [4294967295:0] + slice[4294967295:3] runtime error: slice bounds out of range [4294967295:3] + slice[4294967295:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[4294967295:4294967295] runtime error: slice bounds out of range [:4294967295] with capacity 3 + slice[4294967295:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with capacity 3 + slice[18446744073709551615:0] runtime error: slice bounds out of range [18446744073709551615:0] + slice[18446744073709551615:3] runtime error: slice bounds out of range [18446744073709551615:3] + slice[18446744073709551615:4] runtime error: slice bounds out of range [:4] with capacity 3 + slice[18446744073709551615:4294967295] runtime error: slice bounds out of range [:4294967295] with capacity 3 + slice[18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with capacity 3 + array[0:0] no panic + array[0:3] no panic + array[0:4] runtime error: slice bounds out of range [:4] with length 3 + array[0:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + array[0:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + array[3:0] runtime error: slice bounds out of range [3:0] + array[3:3] no panic + array[3:4] runtime error: slice bounds out of range [:4] with length 3 + array[3:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + array[3:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + array[4:0] runtime error: slice bounds out of range [4:0] + array[4:3] runtime error: slice bounds out of range [4:3] + array[4:4] runtime error: slice bounds out of range [:4] with length 3 + array[4:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + array[4:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + array[4294967295:0] runtime error: slice bounds out of range [4294967295:0] + array[4294967295:3] runtime error: slice bounds out of range [4294967295:3] + array[4294967295:4] runtime error: slice bounds out of range [:4] with length 3 + array[4294967295:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + array[4294967295:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + array[18446744073709551615:0] runtime error: slice bounds out of range [18446744073709551615:0] + array[18446744073709551615:3] runtime error: slice bounds out of range [18446744073709551615:3] + array[18446744073709551615:4] runtime error: slice bounds out of range [:4] with length 3 + array[18446744073709551615:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + array[18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + string[0:0] no panic + string[0:3] no panic + string[0:4] runtime error: slice bounds out of range [:4] with length 3 + string[0:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + string[0:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + string[3:0] runtime error: slice bounds out of range [3:0] + string[3:3] no panic + string[3:4] runtime error: slice bounds out of range [:4] with length 3 + string[3:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + string[3:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + string[4:0] runtime error: slice bounds out of range [4:0] + string[4:3] runtime error: slice bounds out of range [4:3] + string[4:4] runtime error: slice bounds out of range [:4] with length 3 + string[4:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + string[4:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + string[4294967295:0] runtime error: slice bounds out of range [4294967295:0] + string[4294967295:3] runtime error: slice bounds out of range [4294967295:3] + string[4294967295:4] runtime error: slice bounds out of range [:4] with length 3 + string[4294967295:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + string[4294967295:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + string[18446744073709551615:0] runtime error: slice bounds out of range [18446744073709551615:0] + string[18446744073709551615:3] runtime error: slice bounds out of range [18446744073709551615:3] + string[18446744073709551615:4] runtime error: slice bounds out of range [:4] with length 3 + string[18446744073709551615:4294967295] runtime error: slice bounds out of range [:4294967295] with length 3 + string[18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [:18446744073709551615] with length 3 + slice[0:0:0] no panic + slice[0:0:3] no panic + slice[0:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:0:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[0:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[0:3:0] runtime error: slice bounds out of range [:3:0] + slice[0:3:3] no panic + slice[0:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:3:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[0:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[0:4:0] runtime error: slice bounds out of range [:4:0] + slice[0:4:3] runtime error: slice bounds out of range [:4:3] + slice[0:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:4:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[0:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[0:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + slice[0:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + slice[0:4294967295:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[0:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[0:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + slice[0:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + slice[0:18446744073709551615:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[0:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[0:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[3:0:0] runtime error: slice bounds out of range [3:0:] + slice[3:0:3] runtime error: slice bounds out of range [3:0:] + slice[3:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:0:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[3:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[3:3:0] runtime error: slice bounds out of range [:3:0] + slice[3:3:3] no panic + slice[3:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:3:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[3:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[3:4:0] runtime error: slice bounds out of range [:4:0] + slice[3:4:3] runtime error: slice bounds out of range [:4:3] + slice[3:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:4:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[3:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[3:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + slice[3:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + slice[3:4294967295:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[3:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[3:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + slice[3:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + slice[3:18446744073709551615:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[3:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[3:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4:0:0] runtime error: slice bounds out of range [4:0:] + slice[4:0:3] runtime error: slice bounds out of range [4:0:] + slice[4:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:0:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4:3:0] runtime error: slice bounds out of range [:3:0] + slice[4:3:3] runtime error: slice bounds out of range [4:3:] + slice[4:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:3:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4:4:0] runtime error: slice bounds out of range [:4:0] + slice[4:4:3] runtime error: slice bounds out of range [:4:3] + slice[4:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:4:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + slice[4:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + slice[4:4294967295:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + slice[4:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + slice[4:18446744073709551615:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4294967295:0:0] runtime error: slice bounds out of range [4294967295:0:] + slice[4294967295:0:3] runtime error: slice bounds out of range [4294967295:0:] + slice[4294967295:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4294967295:0:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4294967295:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4294967295:3:0] runtime error: slice bounds out of range [:3:0] + slice[4294967295:3:3] runtime error: slice bounds out of range [4294967295:3:] + slice[4294967295:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4294967295:3:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4294967295:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4294967295:4:0] runtime error: slice bounds out of range [:4:0] + slice[4294967295:4:3] runtime error: slice bounds out of range [:4:3] + slice[4294967295:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4294967295:4:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4294967295:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4294967295:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + slice[4294967295:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + slice[4294967295:4294967295:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4294967295:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4294967295:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[4294967295:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + slice[4294967295:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + slice[4294967295:18446744073709551615:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[4294967295:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[4294967295:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[18446744073709551615:0:0] runtime error: slice bounds out of range [18446744073709551615:0:] + slice[18446744073709551615:0:3] runtime error: slice bounds out of range [18446744073709551615:0:] + slice[18446744073709551615:0:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[18446744073709551615:0:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[18446744073709551615:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[18446744073709551615:3:0] runtime error: slice bounds out of range [:3:0] + slice[18446744073709551615:3:3] runtime error: slice bounds out of range [18446744073709551615:3:] + slice[18446744073709551615:3:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[18446744073709551615:3:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[18446744073709551615:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[18446744073709551615:4:0] runtime error: slice bounds out of range [:4:0] + slice[18446744073709551615:4:3] runtime error: slice bounds out of range [:4:3] + slice[18446744073709551615:4:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[18446744073709551615:4:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[18446744073709551615:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[18446744073709551615:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + slice[18446744073709551615:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + slice[18446744073709551615:4294967295:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[18446744073709551615:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[18446744073709551615:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + slice[18446744073709551615:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + slice[18446744073709551615:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + slice[18446744073709551615:18446744073709551615:4] runtime error: slice bounds out of range [::4] with capacity 3 + slice[18446744073709551615:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with capacity 3 + slice[18446744073709551615:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with capacity 3 + array[0:0:0] no panic + array[0:0:3] no panic + array[0:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:0:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[0:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[0:3:0] runtime error: slice bounds out of range [:3:0] + array[0:3:3] no panic + array[0:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:3:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[0:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[0:4:0] runtime error: slice bounds out of range [:4:0] + array[0:4:3] runtime error: slice bounds out of range [:4:3] + array[0:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:4:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[0:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[0:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + array[0:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + array[0:4294967295:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[0:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[0:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + array[0:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + array[0:18446744073709551615:4] runtime error: slice bounds out of range [::4] with length 3 + array[0:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[0:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[3:0:0] runtime error: slice bounds out of range [3:0:] + array[3:0:3] runtime error: slice bounds out of range [3:0:] + array[3:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:0:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[3:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[3:3:0] runtime error: slice bounds out of range [:3:0] + array[3:3:3] no panic + array[3:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:3:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[3:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[3:4:0] runtime error: slice bounds out of range [:4:0] + array[3:4:3] runtime error: slice bounds out of range [:4:3] + array[3:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:4:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[3:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[3:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + array[3:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + array[3:4294967295:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[3:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[3:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + array[3:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + array[3:18446744073709551615:4] runtime error: slice bounds out of range [::4] with length 3 + array[3:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[3:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4:0:0] runtime error: slice bounds out of range [4:0:] + array[4:0:3] runtime error: slice bounds out of range [4:0:] + array[4:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:0:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4:3:0] runtime error: slice bounds out of range [:3:0] + array[4:3:3] runtime error: slice bounds out of range [4:3:] + array[4:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:3:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4:4:0] runtime error: slice bounds out of range [:4:0] + array[4:4:3] runtime error: slice bounds out of range [:4:3] + array[4:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:4:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + array[4:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + array[4:4294967295:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + array[4:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + array[4:18446744073709551615:4] runtime error: slice bounds out of range [::4] with length 3 + array[4:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4294967295:0:0] runtime error: slice bounds out of range [4294967295:0:] + array[4294967295:0:3] runtime error: slice bounds out of range [4294967295:0:] + array[4294967295:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[4294967295:0:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4294967295:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4294967295:3:0] runtime error: slice bounds out of range [:3:0] + array[4294967295:3:3] runtime error: slice bounds out of range [4294967295:3:] + array[4294967295:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[4294967295:3:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4294967295:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4294967295:4:0] runtime error: slice bounds out of range [:4:0] + array[4294967295:4:3] runtime error: slice bounds out of range [:4:3] + array[4294967295:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[4294967295:4:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4294967295:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4294967295:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + array[4294967295:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + array[4294967295:4294967295:4] runtime error: slice bounds out of range [::4] with length 3 + array[4294967295:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4294967295:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[4294967295:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + array[4294967295:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + array[4294967295:18446744073709551615:4] runtime error: slice bounds out of range [::4] with length 3 + array[4294967295:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[4294967295:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[18446744073709551615:0:0] runtime error: slice bounds out of range [18446744073709551615:0:] + array[18446744073709551615:0:3] runtime error: slice bounds out of range [18446744073709551615:0:] + array[18446744073709551615:0:4] runtime error: slice bounds out of range [::4] with length 3 + array[18446744073709551615:0:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[18446744073709551615:0:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[18446744073709551615:3:0] runtime error: slice bounds out of range [:3:0] + array[18446744073709551615:3:3] runtime error: slice bounds out of range [18446744073709551615:3:] + array[18446744073709551615:3:4] runtime error: slice bounds out of range [::4] with length 3 + array[18446744073709551615:3:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[18446744073709551615:3:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[18446744073709551615:4:0] runtime error: slice bounds out of range [:4:0] + array[18446744073709551615:4:3] runtime error: slice bounds out of range [:4:3] + array[18446744073709551615:4:4] runtime error: slice bounds out of range [::4] with length 3 + array[18446744073709551615:4:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[18446744073709551615:4:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[18446744073709551615:4294967295:0] runtime error: slice bounds out of range [:4294967295:0] + array[18446744073709551615:4294967295:3] runtime error: slice bounds out of range [:4294967295:3] + array[18446744073709551615:4294967295:4] runtime error: slice bounds out of range [::4] with length 3 + array[18446744073709551615:4294967295:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[18446744073709551615:4294967295:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 + array[18446744073709551615:18446744073709551615:0] runtime error: slice bounds out of range [:18446744073709551615:0] + array[18446744073709551615:18446744073709551615:3] runtime error: slice bounds out of range [:18446744073709551615:3] + array[18446744073709551615:18446744073709551615:4] runtime error: slice bounds out of range [::4] with length 3 + array[18446744073709551615:18446744073709551615:4294967295] runtime error: slice bounds out of range [::4294967295] with length 3 + array[18446744073709551615:18446744073709551615:18446744073709551615] runtime error: slice bounds out of range [::18446744073709551615] with length 3 diff --git a/test/fixedbugs/issue30243.go b/test/fixedbugs/issue30243.go new file mode 100644 index 00000000..51fd204c --- /dev/null +++ b/test/fixedbugs/issue30243.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2019 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. + +// Compile-time constants, even if they cannot be represented +// accurately, should remain the same in operations that don't +// affect their values. + +package main + +import "fmt" + +func main() { + const x = 0.01 + const xi = 0.01i + const xc = complex(0, x) + + if imag(xi) != x { + fmt.Printf("FAILED: %g != %g\n", imag(xi), x) + } + + if xi != complex(0, x) { + fmt.Printf("FAILED: %g != %g\n", xi, complex(0, x)) + } +} diff --git a/test/fixedbugs/issue30430.go b/test/fixedbugs/issue30430.go new file mode 100644 index 00000000..6c27b828 --- /dev/null +++ b/test/fixedbugs/issue30430.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2019 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. + +// Issue 30430: isGoConst returned true for non-const variables, +// resulting in ICE. + +package p + +func f() { + var s string + _ = map[string]string{s: ""} +} + +const s = "" diff --git a/test/fixedbugs/issue30606.go b/test/fixedbugs/issue30606.go new file mode 100644 index 00000000..bc31982e --- /dev/null +++ b/test/fixedbugs/issue30606.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2019 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. + +package main + +import "reflect" + +func main() {} + +func typ(x interface{}) reflect.Type { return reflect.ValueOf(x).Type() } + +var x = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F5", Type: reflect.StructOf([]reflect.StructField{ + {Name: "F4", Type: reflect.ArrayOf(5462, + reflect.SliceOf(typ(uint64(0))))}, + })}, +})) diff --git a/test/fixedbugs/issue30606b.go b/test/fixedbugs/issue30606b.go new file mode 100644 index 00000000..2ce2804a --- /dev/null +++ b/test/fixedbugs/issue30606b.go @@ -0,0 +1,51 @@ +// run + +// Copyright 2019 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. + +package main + +import "reflect" + +func main() {} + +func typ(x interface{}) reflect.Type { return reflect.ValueOf(x).Type() } + +var byteType = typ((byte)(0)) +var ptrType = typ((*byte)(nil)) + +// Arrays of pointers. There are two size thresholds. +// Bit masks are chunked in groups of 120 pointers. +// Array types with >16384 pointers have a GC program instead of a bitmask. +var smallPtrType = reflect.ArrayOf(100, ptrType) +var mediumPtrType = reflect.ArrayOf(1000, ptrType) +var bigPtrType = reflect.ArrayOf(16385, ptrType) + +var x0 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: byteType}, + {Name: "F2", Type: bigPtrType}, +})) +var x1 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: smallPtrType}, + {Name: "F2", Type: bigPtrType}, +})) +var x2 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: mediumPtrType}, + {Name: "F2", Type: bigPtrType}, +})) +var x3 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: ptrType}, + {Name: "F2", Type: byteType}, + {Name: "F3", Type: bigPtrType}, +})) +var x4 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: ptrType}, + {Name: "F2", Type: smallPtrType}, + {Name: "F3", Type: bigPtrType}, +})) +var x5 = reflect.New(reflect.StructOf([]reflect.StructField{ + {Name: "F1", Type: ptrType}, + {Name: "F2", Type: mediumPtrType}, + {Name: "F3", Type: bigPtrType}, +})) diff --git a/test/fixedbugs/issue30659.dir/a.go b/test/fixedbugs/issue30659.dir/a.go new file mode 100644 index 00000000..3837e021 --- /dev/null +++ b/test/fixedbugs/issue30659.dir/a.go @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +package a + +type I interface { + I2 +} +type I2 interface { + M() +} +type S struct{} + +func (*S) M() {} + +func New() I { + return &S{} +} diff --git a/test/fixedbugs/issue30659.dir/b.go b/test/fixedbugs/issue30659.dir/b.go new file mode 100644 index 00000000..272e5205 --- /dev/null +++ b/test/fixedbugs/issue30659.dir/b.go @@ -0,0 +1,13 @@ +// Copyright 2019 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. + +package b + +import ( + "./a" +) + +func B(p1 a.I, p2 a.I2) int { + return 42 +} diff --git a/test/fixedbugs/issue30659.go b/test/fixedbugs/issue30659.go new file mode 100644 index 00000000..973ae1dc --- /dev/null +++ b/test/fixedbugs/issue30659.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue30679.go b/test/fixedbugs/issue30679.go new file mode 100644 index 00000000..4d0df18f --- /dev/null +++ b/test/fixedbugs/issue30679.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2019 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. + +package main + +func main() { + var f float64 + var p, q *float64 + + p = &f + if *q > 0 { + p = q + } + _ = *p +} diff --git a/test/fixedbugs/issue30709.go b/test/fixedbugs/issue30709.go new file mode 100644 index 00000000..49524540 --- /dev/null +++ b/test/fixedbugs/issue30709.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2019 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. + +// Check closure in const declaration group can be compiled +// and set correct value + +package main + +import "unsafe" + +const ( + x = unsafe.Sizeof(func() {}) + y +) + +func main() { + const ( + z = unsafe.Sizeof(func() {}) + t + ) + + // x and y must be equal + println(x == y) + // size must be greater than zero + println(y > 0) + + // Same logic as x, y above + println(z == t) + println(t > 0) +} diff --git a/test/fixedbugs/issue30709.out b/test/fixedbugs/issue30709.out new file mode 100644 index 00000000..1140ff52 --- /dev/null +++ b/test/fixedbugs/issue30709.out @@ -0,0 +1,4 @@ +true +true +true +true diff --git a/test/fixedbugs/issue30722.go b/test/fixedbugs/issue30722.go new file mode 100644 index 00000000..02258f0b --- /dev/null +++ b/test/fixedbugs/issue30722.go @@ -0,0 +1,17 @@ +// errorcheck + +// Copyright 2019 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. + +// Verify that we only get one error per invalid integer literal. + +package p + +const ( + _ = 1_ // ERROR "'_' must separate successive digits" + _ = 0b // ERROR "binary literal has no digits" + _ = 0o // ERROR "octal literal has no digits" + _ = 0x // ERROR "hexadecimal literal has no digits" + _ = 0xde__ad // ERROR "'_' must separate successive digits" +) diff --git a/test/fixedbugs/issue30862.dir/a.go b/test/fixedbugs/issue30862.dir/a.go new file mode 100644 index 00000000..c23f4de1 --- /dev/null +++ b/test/fixedbugs/issue30862.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package a + +var pl int + +type NoitfStruct struct { + F int + G int +} + +//go:nointerface +func (t *NoitfStruct) NoInterfaceMethod() {} diff --git a/test/fixedbugs/issue30862.dir/b.go b/test/fixedbugs/issue30862.dir/b.go new file mode 100644 index 00000000..3e501bb8 --- /dev/null +++ b/test/fixedbugs/issue30862.dir/b.go @@ -0,0 +1,29 @@ +// Copyright 2019 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. + +package b + +import "./a" + +type EmbedImported struct { + a.NoitfStruct +} + +func Test() []string { + bad := []string{} + x := interface{}(new(a.NoitfStruct)) + if _, ok := x.(interface { + NoInterfaceMethod() + }); ok { + bad = append(bad, "fail 1") + } + + x = interface{}(new(EmbedImported)) + if _, ok := x.(interface { + NoInterfaceMethod() + }); ok { + bad = append(bad, "fail 2") + } + return bad +} diff --git a/test/fixedbugs/issue30862.dir/main.go b/test/fixedbugs/issue30862.dir/main.go new file mode 100644 index 00000000..80db0e13 --- /dev/null +++ b/test/fixedbugs/issue30862.dir/main.go @@ -0,0 +1,28 @@ +// Copyright 2019 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. + +package main + +import ( + "fmt" + "os" + + "./b" +) + +// Test case for issue 30862. + +// Be aware that unless GOEXPERIMENT=fieldtrack is set when building +// the compiler, this test will fail if executed with a regular GC +// compiler. + +func main() { + bad := b.Test() + if len(bad) > 0 { + for _, s := range bad { + fmt.Fprintf(os.Stderr, "test failed: %s\n", s) + } + os.Exit(1) + } +} diff --git a/test/fixedbugs/issue30862.go b/test/fixedbugs/issue30862.go new file mode 100644 index 00000000..ba122cc3 --- /dev/null +++ b/test/fixedbugs/issue30862.go @@ -0,0 +1,14 @@ +// rundir + +// Copyright 2019 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 case for issue 30862. This test as written will +// fail for the main 'gc' compiler unless GOEXPERIMENT=fieldtrack +// is set when building it, whereas gccgo has field tracking +// enabled by default (hence the build tag below). + +// +build gccgo + +package ignored diff --git a/test/fixedbugs/issue30898.go b/test/fixedbugs/issue30898.go new file mode 100644 index 00000000..012d5a26 --- /dev/null +++ b/test/fixedbugs/issue30898.go @@ -0,0 +1,19 @@ +// errorcheck -0 -m + +// Copyright 2019 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 functions with variadic arguments + +package foo + +func debugf(format string, args ...interface{}) { // ERROR "can inline debugf" "format does not escape" "args does not escape" + // Dummy implementation for non-debug build. + // A non-empty implementation would be enabled with a build tag. +} + +func bar() { // ERROR "can inline bar" + value := 10 + debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\[\]interface {} literal does not escape" +} diff --git a/test/fixedbugs/issue30907.dir/a.go b/test/fixedbugs/issue30907.dir/a.go new file mode 100644 index 00000000..e1a5c0cc --- /dev/null +++ b/test/fixedbugs/issue30907.dir/a.go @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +package a + +type UUID string + +func New() UUID { + return Must(NewRandom()) +} + +func NewRandom() (UUID, error) { + return "", nil +} + +func Must(uuid UUID, err error) UUID { + return uuid +} diff --git a/test/fixedbugs/issue30907.dir/b.go b/test/fixedbugs/issue30907.dir/b.go new file mode 100644 index 00000000..f4f5fc4f --- /dev/null +++ b/test/fixedbugs/issue30907.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2019 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. + +package p + +import "./a" + +func F() { + a.New() +} diff --git a/test/fixedbugs/issue30907.go b/test/fixedbugs/issue30907.go new file mode 100644 index 00000000..973ae1dc --- /dev/null +++ b/test/fixedbugs/issue30907.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue30908.dir/a.go b/test/fixedbugs/issue30908.dir/a.go new file mode 100644 index 00000000..2f0abc37 --- /dev/null +++ b/test/fixedbugs/issue30908.dir/a.go @@ -0,0 +1,32 @@ +// Copyright 2019 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. + +package a + +import ( + "errors" + "strings" +) + +var G interface{} + +func Unmarshal(data []byte, o interface{}) error { + G = o + v, ok := o.(*map[string]interface{}) + if !ok { + return errors.New("eek") + } + vals := make(map[string]interface{}) + s := string(data) + items := strings.Split(s, " ") + var err error + for _, item := range items { + vals[item] = s + if item == "error" { + err = errors.New("ouch") + } + } + *v = vals + return err +} diff --git a/test/fixedbugs/issue30908.dir/b.go b/test/fixedbugs/issue30908.dir/b.go new file mode 100644 index 00000000..2f543985 --- /dev/null +++ b/test/fixedbugs/issue30908.dir/b.go @@ -0,0 +1,35 @@ +// Copyright 2019 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. + +package b + +import ( + "io/ioutil" + + "./a" +) + +var G int + +// An inlinable function. To trigger the bug in question this needs +// to be inlined here within the package and also inlined into some +// other package that imports it. +func ReadValues(data []byte) (vals map[string]interface{}, err error) { + err = a.Unmarshal(data, &vals) + if len(vals) == 0 { + vals = map[string]interface{}{} + } + return +} + +// A local call to the function above, which triggers the "move to heap" +// of the output param. +func CallReadValues(filename string) (map[string]interface{}, error) { + defer func() { G++ }() + data, err := ioutil.ReadFile(filename) + if err != nil { + return map[string]interface{}{}, err + } + return ReadValues(data) +} diff --git a/test/fixedbugs/issue30908.dir/m.go b/test/fixedbugs/issue30908.dir/m.go new file mode 100644 index 00000000..a170a6ee --- /dev/null +++ b/test/fixedbugs/issue30908.dir/m.go @@ -0,0 +1,21 @@ +// Copyright 2019 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. + +package main + +import ( + "os" + + "./b" +) + +func main() { + seed := "some things are better" + bsl := []byte(seed) + b.CallReadValues("/dev/null") + vals, err := b.ReadValues(bsl) + if vals["better"] != seed || err != nil { + os.Exit(1) + } +} diff --git a/test/fixedbugs/issue30908.go b/test/fixedbugs/issue30908.go new file mode 100644 index 00000000..60fbd114 --- /dev/null +++ b/test/fixedbugs/issue30908.go @@ -0,0 +1,9 @@ +// rundir -P -ldflags -strictdups=2 -w=0 + +// Copyright 2019 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. + +// +build !nacl,!js + +package ignored diff --git a/test/fixedbugs/issue30956.go b/test/fixedbugs/issue30956.go new file mode 100644 index 00000000..021e6c5d --- /dev/null +++ b/test/fixedbugs/issue30956.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2019 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. + +// Check for compile generated static data for literal +// composite struct + +package main + +import "fmt" + +type X struct { + V interface{} + + a int + b int + c int +} + +func pr(x X) { + fmt.Println(x.V) +} + +func main() { + pr(X{ + V: struct { + A int + }{42}, + }) +} diff --git a/test/fixedbugs/issue30956.out b/test/fixedbugs/issue30956.out new file mode 100644 index 00000000..04f25e8a --- /dev/null +++ b/test/fixedbugs/issue30956.out @@ -0,0 +1 @@ +{42} diff --git a/test/fixedbugs/issue30977.go b/test/fixedbugs/issue30977.go new file mode 100644 index 00000000..2ca040d7 --- /dev/null +++ b/test/fixedbugs/issue30977.go @@ -0,0 +1,52 @@ +// run + +// Copyright 2019 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. + +// Issue 30977: write barrier call clobbers volatile +// value when there are multiple uses of the value. + +package main + +import "runtime" + +type T struct { + a, b, c, d, e string +} + +//go:noinline +func g() T { + return T{"a", "b", "c", "d", "e"} +} + +//go:noinline +func f() { + // The compiler optimizes this to direct copying + // the call result to both globals, with write + // barriers. The first write barrier call clobbers + // the result of g on stack. + X = g() + Y = X +} + +var X, Y T + +const N = 1000 + +func main() { + // Keep GC running so the write barrier is on. + go func() { + for { + runtime.GC() + } + }() + + for i := 0; i < N; i++ { + runtime.Gosched() + f() + if X != Y { + panic("FAIL") + } + } +} diff --git a/test/fixedbugs/issue31010.go b/test/fixedbugs/issue31010.go new file mode 100644 index 00000000..836e85fd --- /dev/null +++ b/test/fixedbugs/issue31010.go @@ -0,0 +1,24 @@ +// compile + +// Copyright 2019 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. + +package p + +var ( + x int + xs []int +) + +func a([]int) (int, error) + +func b() (int, error) { + return a(append(xs, x)) +} + +func c(int, error) (int, error) + +func d() (int, error) { + return c(b()) +} diff --git a/test/fixedbugs/issue31060.go b/test/fixedbugs/issue31060.go new file mode 100644 index 00000000..a1ba7051 --- /dev/null +++ b/test/fixedbugs/issue31060.go @@ -0,0 +1,30 @@ +// errorcheck + +// Copyright 2019 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. + +package p + +const ( + f = 1.0 + c = 1.0i + + _ = ^f // ERROR "invalid operation|expected integer" + _ = ^c // ERROR "invalid operation|expected integer" + + _ = f % f // ERROR "invalid operation|expected integer" + _ = c % c // ERROR "invalid operation|expected integer" + + _ = f & f // ERROR "invalid operation|expected integer" + _ = c & c // ERROR "invalid operation|expected integer" + + _ = f | f // ERROR "invalid operation|expected integer" + _ = c | c // ERROR "invalid operation|expected integer" + + _ = f ^ f // ERROR "invalid operation|expected integer" + _ = c ^ c // ERROR "invalid operation|expected integer" + + _ = f &^ f // ERROR "invalid operation|expected integer" + _ = c &^ c // ERROR "invalid operation|expected integer" +) diff --git a/test/fixedbugs/issue31252.dir/a.go b/test/fixedbugs/issue31252.dir/a.go new file mode 100644 index 00000000..fa431502 --- /dev/null +++ b/test/fixedbugs/issue31252.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2019 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. + +package a + +import "fmt" + +type IndexController struct{} + +func (this *IndexController) Index(m *string) { + fmt.Println(m) +} diff --git a/test/fixedbugs/issue31252.dir/b.go b/test/fixedbugs/issue31252.dir/b.go new file mode 100644 index 00000000..9bfc0ff9 --- /dev/null +++ b/test/fixedbugs/issue31252.dir/b.go @@ -0,0 +1,13 @@ +// Copyright 2019 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. + +package b + +import "fmt" + +type IndexController struct{} + +func (this *IndexController) Index(m *string) { + fmt.Println(m) +} diff --git a/test/fixedbugs/issue31252.dir/c.go b/test/fixedbugs/issue31252.dir/c.go new file mode 100644 index 00000000..928c8eee --- /dev/null +++ b/test/fixedbugs/issue31252.dir/c.go @@ -0,0 +1,26 @@ +// Copyright 2019 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. + +package c + +import ( + "a" + "b" +) + +type HandlerFunc func(*string) + +func RouterInit() { + //home API + homeIndex := &a.IndexController{} + GET("/home/index/index", homeIndex.Index) + //admin API + adminIndex := &b.IndexController{} + GET("/admin/index/index", adminIndex.Index) + return +} + +func GET(path string, handlers ...HandlerFunc) { + return +} diff --git a/test/fixedbugs/issue31252.dir/main.go b/test/fixedbugs/issue31252.dir/main.go new file mode 100644 index 00000000..25a75486 --- /dev/null +++ b/test/fixedbugs/issue31252.dir/main.go @@ -0,0 +1,11 @@ +// Copyright 2019 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. + +package main + +import "c" + +func main() { + c.RouterInit() +} diff --git a/test/fixedbugs/issue31252.go b/test/fixedbugs/issue31252.go new file mode 100644 index 00000000..973ae1dc --- /dev/null +++ b/test/fixedbugs/issue31252.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue31412a.go b/test/fixedbugs/issue31412a.go new file mode 100644 index 00000000..75021c68 --- /dev/null +++ b/test/fixedbugs/issue31412a.go @@ -0,0 +1,32 @@ +// compile + +// Copyright 2019 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. + +// This code was incorrectly flagged as erroneous by gccgo. + +package main + +type Name string + +type EFunc func(int) int + +func Register(f EFunc, names ...Name) int { + return f(len(names)) +} + +const ( + B Name = "B" +) + +func RegisterIt() { + n := B + "Duck" + d := B + "Goose" + f := func(x int) int { return x + 9 } + Register(f, n, d) +} + +func main() { + RegisterIt() +} diff --git a/test/fixedbugs/issue31412b.go b/test/fixedbugs/issue31412b.go new file mode 100644 index 00000000..6c4ec00d --- /dev/null +++ b/test/fixedbugs/issue31412b.go @@ -0,0 +1,20 @@ +// errorcheck + +// Copyright 2019 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. + +// This code was incorrectly accepted by gccgo. + +package main + +type N string +type M string + +const B N = "B" +const C M = "C" + +func main() { + q := B + C // ERROR "mismatched types|incompatible types" + println(q) +} diff --git a/test/fixedbugs/issue31419.go b/test/fixedbugs/issue31419.go new file mode 100644 index 00000000..233111ae --- /dev/null +++ b/test/fixedbugs/issue31419.go @@ -0,0 +1,58 @@ +// run + +// Copyright 2019 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. + +// Issue 31419: race in getitab when two goroutines try +// to do the same failed interface conversion. + +package main + +type T int + +func (t T) M() {} + +type I interface { + M() + M2() +} + +var t T +var e interface{} = &t +var ok = false +var ch = make(chan int) + +func main() { + _, ok = e.(I) // populate itab cache with a false result + + go f() // get itab in a loop + + var i I + for k := 0; k < 10000; k++ { + i, ok = e.(I) // read the cached itab + if ok { + println("iteration", k, "i =", i, "&t =", &t) + panic("conversion succeeded") + } + } + <-ch +} + +func f() { + for i := 0; i < 10000; i++ { + f1() + } + ch <- 1 +} + +func f1() { + defer func() { + err := recover() + if err == nil { + panic("did not panic") + } + }() + i := e.(I) // triggers itab.init, for getting the panic string + _ = i +} diff --git a/test/fixedbugs/issue31546.go b/test/fixedbugs/issue31546.go new file mode 100644 index 00000000..a459d4d1 --- /dev/null +++ b/test/fixedbugs/issue31546.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2019 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. + +package main + +import ( + "reflect" +) + +var x = struct{ a, _, c int }{1, 2, 3} + +func main() { + if i := reflect.ValueOf(x).Field(1).Int(); i != 0 { + println("got", i, "want", 0) + panic("fail") + } +} diff --git a/test/fixedbugs/issue31573.go b/test/fixedbugs/issue31573.go new file mode 100644 index 00000000..fb4fdc81 --- /dev/null +++ b/test/fixedbugs/issue31573.go @@ -0,0 +1,49 @@ +// errorcheck -0 -m + +// Copyright 2019 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. + +package p + +func f(...*int) {} // ERROR "can inline f$" + +func g() { + defer f() // ERROR "... argument does not escape$" + defer f(new(int)) // ERROR "... argument does not escape$" "new\(int\) does not escape$" + defer f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) does not escape$" + + defer f(nil...) + defer f([]*int{}...) // ERROR "\[\]\*int literal does not escape$" + defer f([]*int{new(int)}...) // ERROR "\[\]\*int literal does not escape$" "new\(int\) does not escape$" + defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal does not escape$" "new\(int\) does not escape$" + + go f() // ERROR "... argument escapes to heap$" + go f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + + go f(nil...) + go f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" + go f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + + for { + defer f() // ERROR "... argument escapes to heap$" + defer f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + defer f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + + defer f(nil...) + defer f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" + defer f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + + go f() // ERROR "... argument escapes to heap$" + go f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" + + go f(nil...) + go f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" + go f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + } +} diff --git a/test/fixedbugs/issue31636.dir/a.go b/test/fixedbugs/issue31636.dir/a.go new file mode 100644 index 00000000..e57e0d5f --- /dev/null +++ b/test/fixedbugs/issue31636.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2019 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. + +package a + +func init() { + println("a") +} diff --git a/test/fixedbugs/issue31636.dir/b.go b/test/fixedbugs/issue31636.dir/b.go new file mode 100644 index 00000000..990e6820 --- /dev/null +++ b/test/fixedbugs/issue31636.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2019 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. + +package b + +func init() { + println("b") +} diff --git a/test/fixedbugs/issue31636.dir/c.go b/test/fixedbugs/issue31636.dir/c.go new file mode 100644 index 00000000..e53529aa --- /dev/null +++ b/test/fixedbugs/issue31636.dir/c.go @@ -0,0 +1,9 @@ +// Copyright 2019 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. + +package c + +func init() { + println("c") +} diff --git a/test/fixedbugs/issue31636.dir/main.go b/test/fixedbugs/issue31636.dir/main.go new file mode 100644 index 00000000..d8ae902c --- /dev/null +++ b/test/fixedbugs/issue31636.dir/main.go @@ -0,0 +1,20 @@ +// Copyright 2019 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. + +package main + +// We want the initializers of these packages to occur in source code +// order. See issue 31636. This is the behavior up to and including +// 1.13. For 1.14, we will move to a variant of lexicographic ordering +// which will require a change to the test output of this test. +import ( + _ "c" + + _ "b" + + _ "a" +) + +func main() { +} diff --git a/test/fixedbugs/issue31636.go b/test/fixedbugs/issue31636.go new file mode 100644 index 00000000..af6f1341 --- /dev/null +++ b/test/fixedbugs/issue31636.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue31636.out b/test/fixedbugs/issue31636.out new file mode 100644 index 00000000..e274b2bb --- /dev/null +++ b/test/fixedbugs/issue31636.out @@ -0,0 +1,3 @@ +c +b +a diff --git a/test/fixedbugs/issue31637.dir/a.go b/test/fixedbugs/issue31637.dir/a.go new file mode 100644 index 00000000..71f39269 --- /dev/null +++ b/test/fixedbugs/issue31637.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package a + +type dO struct { + x int +} + +type EDO struct{} + +func (EDO) Apply(*dO) {} + +var X EDO diff --git a/test/fixedbugs/issue31637.dir/b.go b/test/fixedbugs/issue31637.dir/b.go new file mode 100644 index 00000000..ce83b000 --- /dev/null +++ b/test/fixedbugs/issue31637.dir/b.go @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +package main + +import "./a" + +type No struct { + a.EDO +} + +func X() No { + return No{} +} + +func main() { + X() +} diff --git a/test/fixedbugs/issue31637.go b/test/fixedbugs/issue31637.go new file mode 100644 index 00000000..dcfb4a7e --- /dev/null +++ b/test/fixedbugs/issue31637.go @@ -0,0 +1,11 @@ +// compiledir + +// Copyright 2019 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. + +// This directory contains a pair of packages that triggered +// a compiler crash in gollvm (problem in handling an inlinable +// method with unnamed parameter). See issue 31637 for details. + +package ignored diff --git a/test/fixedbugs/issue31747.go b/test/fixedbugs/issue31747.go new file mode 100644 index 00000000..dfb585c6 --- /dev/null +++ b/test/fixedbugs/issue31747.go @@ -0,0 +1,34 @@ +// errorcheck -lang=go1.12 + +// Copyright 2019 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. + +package p + +// numeric literals +const ( + _ = 1_000 // ERROR "underscores in numeric literals only supported as of -lang=go1.13" + _ = 0b111 // ERROR "binary literals only supported as of -lang=go1.13" + _ = 0o567 // ERROR "0o/0O-style octal literals only supported as of -lang=go1.13" + _ = 0xabc // ok + _ = 0x0p1 // ERROR "hexadecimal floating-point literals only supported as of -lang=go1.13" + + _ = 0B111 // ERROR "binary" + _ = 0O567 // ERROR "octal" + _ = 0Xabc // ok + _ = 0X0P1 // ERROR "hexadecimal floating-point" + + _ = 1_000i // ERROR "underscores" + _ = 0b111i // ERROR "binary" + _ = 0o567i // ERROR "octal" + _ = 0xabci // ERROR "hexadecimal floating-point" + _ = 0x0p1i // ERROR "hexadecimal floating-point" +) + +// signed shift counts +var ( + s int + _ = 1 << s // ERROR "signed shift count type int, only supported as of -lang=go1.13" + _ = 1 >> s // ERROR "signed shift count" +) diff --git a/test/fixedbugs/issue31777.go b/test/fixedbugs/issue31777.go new file mode 100644 index 00000000..839e242c --- /dev/null +++ b/test/fixedbugs/issue31777.go @@ -0,0 +1,24 @@ +// compile + +// Copyright 2019 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. + +// Compile with static map literal. + +package p + +type i interface { + j() +} + +type s struct{} + +func (s) j() {} + +type foo map[string]i + +var f = foo{ + "1": s{}, + "2": s{}, +} diff --git a/test/fixedbugs/issue31782.go b/test/fixedbugs/issue31782.go new file mode 100644 index 00000000..a42001ea --- /dev/null +++ b/test/fixedbugs/issue31782.go @@ -0,0 +1,24 @@ +// run + +// Copyright 2019 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. + +// Check static composite literal reports wrong for struct +// field. + +package main + +type one struct { + i interface{} +} + +type two struct { + i interface{} + s []string +} + +func main() { + o := one{i: two{i: 42}.i} + println(o.i.(int)) +} diff --git a/test/fixedbugs/issue31782.out b/test/fixedbugs/issue31782.out new file mode 100644 index 00000000..d81cc071 --- /dev/null +++ b/test/fixedbugs/issue31782.out @@ -0,0 +1 @@ +42 diff --git a/test/fixedbugs/issue31915.go b/test/fixedbugs/issue31915.go new file mode 100644 index 00000000..96af175e --- /dev/null +++ b/test/fixedbugs/issue31915.go @@ -0,0 +1,23 @@ +// compile -d=ssa/check/on + +// Copyright 2019 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. + +package p + +func f() + +func g() { + var a []int + var b bool + for { + b = (b && b) != (b && b) + for b && b == b || true { + f() + _ = a[0] + } + _ = &b + a = []int{} + } +} diff --git a/test/fixedbugs/issue31959.dir/a.go b/test/fixedbugs/issue31959.dir/a.go new file mode 100644 index 00000000..6c7ffa38 --- /dev/null +++ b/test/fixedbugs/issue31959.dir/a.go @@ -0,0 +1,12 @@ +// Copyright 2019 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. + +package a + +type T struct{} + +func F() { + type T = int + println(T(0)) +} diff --git a/test/fixedbugs/issue31959.dir/main.go b/test/fixedbugs/issue31959.dir/main.go new file mode 100644 index 00000000..895c4e53 --- /dev/null +++ b/test/fixedbugs/issue31959.dir/main.go @@ -0,0 +1,21 @@ +// run + +// Copyright 2019 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. + +// Check import package contains type alias in function +// with the same name with an export type not panic + +package main + +import ( + "fmt" + + "a" +) + +func main() { + fmt.Println(a.T{}) + a.F() +} diff --git a/test/fixedbugs/issue31959.go b/test/fixedbugs/issue31959.go new file mode 100644 index 00000000..af6f1341 --- /dev/null +++ b/test/fixedbugs/issue31959.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue31959.out b/test/fixedbugs/issue31959.out new file mode 100644 index 00000000..8ddcb67a --- /dev/null +++ b/test/fixedbugs/issue31959.out @@ -0,0 +1,2 @@ +{} +0 diff --git a/test/fixedbugs/issue31987.go b/test/fixedbugs/issue31987.go new file mode 100644 index 00000000..372289b5 --- /dev/null +++ b/test/fixedbugs/issue31987.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2019 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. + +package main + +import "fmt" + +type container struct { + Value string +} + +func main() { + s := []container{ + 7: {Value: "string value"}, + } + if s[7].Value != "string value" { + panic(fmt.Errorf("wanted \"string value\", got \"%s\"", s[7].Value)) + } +} diff --git a/test/fixedbugs/issue32175.go b/test/fixedbugs/issue32175.go new file mode 100644 index 00000000..a6773514 --- /dev/null +++ b/test/fixedbugs/issue32175.go @@ -0,0 +1,22 @@ +// run + +// Copyright 2019 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. + +package main + +// This used to print 0, because x was incorrectly captured by value. + +func f() (x int) { + defer func() func() { + return func() { + println(x) + } + }()() + return 42 +} + +func main() { + f() +} diff --git a/test/fixedbugs/issue32175.out b/test/fixedbugs/issue32175.out new file mode 100644 index 00000000..d81cc071 --- /dev/null +++ b/test/fixedbugs/issue32175.out @@ -0,0 +1 @@ +42 diff --git a/test/fixedbugs/issue32288.go b/test/fixedbugs/issue32288.go new file mode 100644 index 00000000..91c930c0 --- /dev/null +++ b/test/fixedbugs/issue32288.go @@ -0,0 +1,48 @@ +// run + +// Copyright 2019 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. + +package main + +type T struct { + s [1]string + pad [16]uintptr +} + +//go:noinline +func f(t *int, p *int) []T { + var res []T + for { + var e *T + res = append(res, *e) + } +} + +func main() { + defer func() { + useStack(100) // force a stack copy + // We're expecting a panic. + // The bug in this issue causes a throw, which this recover() will not squash. + recover() + }() + junk() // fill the stack with invalid pointers + f(nil, nil) +} + +func useStack(n int) { + if n == 0 { + return + } + useStack(n - 1) +} + +//go:noinline +func junk() uintptr { + var a [128]uintptr // 1k of bad pointers on the stack + for i := range a { + a[i] = 0xaa + } + return a[12] +} diff --git a/test/fixedbugs/issue32347.go b/test/fixedbugs/issue32347.go new file mode 100644 index 00000000..91c038a5 --- /dev/null +++ b/test/fixedbugs/issue32347.go @@ -0,0 +1,18 @@ +// compile + +// Copyright 2019 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. + +// Issue 32347: gccgo compiler crashes with int-to-string conversion +// with large integer constant operand. + +package p + +const ( + X1 = string(128049) + X2 = string(-1) + X3 = string(1<<48) +) + +var S1, S2, S3 = X1, X2, X3 diff --git a/test/fixedbugs/issue32477.go b/test/fixedbugs/issue32477.go new file mode 100644 index 00000000..8b3c1752 --- /dev/null +++ b/test/fixedbugs/issue32477.go @@ -0,0 +1,71 @@ +// run + +// Copyright 2019 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. + +// Make sure we use the deferreturn live map instead of +// the entry live map when handling a segv in a function +// that defers. + +package main + +import "runtime" + +var finalized bool +var err string + +type HeapObj [8]int64 + +const filler int64 = 0x123456789abcdef0 + +func (h *HeapObj) init() { + for i := 0; i < len(*h); i++ { + h[i] = filler + } +} +func (h *HeapObj) check() { + for i := 0; i < len(*h); i++ { + if h[i] != filler { + err = "filler overwritten" + } + } +} + +func gc(shouldFinalize bool) { + runtime.GC() + runtime.GC() + runtime.GC() + if shouldFinalize != finalized { + err = "heap object finalized at the wrong time" + } +} + +func main() { + h := new(HeapObj) + h.init() + runtime.SetFinalizer(h, func(h *HeapObj) { + finalized = true + }) + + gc(false) + g(h) + if err != "" { + panic(err) + } +} + +func g(h *HeapObj) { + gc(false) + h.check() + // h is now unused + defer func() { + // h should not be live here. Previously we used to + // use the function entry point as the place to get + // the live map when handling a segv. + gc(true) + recover() + }() + *(*int)(nil) = 0 // trigger a segv + return +} diff --git a/test/fixedbugs/issue32560.go b/test/fixedbugs/issue32560.go new file mode 100644 index 00000000..c6f72b6b --- /dev/null +++ b/test/fixedbugs/issue32560.go @@ -0,0 +1,51 @@ +// run + +// Copyright 2019 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. + +// Values smaller than 64-bits were mistakenly always proven to be +// non-negative. +// +// The tests here are marked go:noinline to ensure they're +// independently optimized by SSA. + +package main + +var x int32 = -1 + +//go:noinline +func a() { + if x != -1 { + panic(1) + } + if x > 0 || x != -1 { + panic(2) + } +} + +//go:noinline +func b() { + if x != -1 { + panic(3) + } + if x > 0 { + panic(4) + } +} + +//go:noinline +func c() { + if x > 0 || x != -1 { + panic(5) + } + if x > 0 || x != -1 { + panic(6) + } +} + +func main() { + a() + b() + c() +} diff --git a/test/fixedbugs/issue32595.dir/a.go b/test/fixedbugs/issue32595.dir/a.go new file mode 100644 index 00000000..8342dd5c --- /dev/null +++ b/test/fixedbugs/issue32595.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2019 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. + +package a + +func A() { + defer func() {}() +} diff --git a/test/fixedbugs/issue32595.dir/b.go b/test/fixedbugs/issue32595.dir/b.go new file mode 100644 index 00000000..9a13a575 --- /dev/null +++ b/test/fixedbugs/issue32595.dir/b.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package b + +import "reflect" + +func B() { + t1 := reflect.TypeOf([0]byte{}) + t2 := reflect.TypeOf(new([0]byte)).Elem() + if t1 != t2 { + panic("[0]byte types do not match") + } +} diff --git a/test/fixedbugs/issue32595.dir/main.go b/test/fixedbugs/issue32595.dir/main.go new file mode 100644 index 00000000..20472cd7 --- /dev/null +++ b/test/fixedbugs/issue32595.dir/main.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package main + +import ( + "a" + "b" +) + +func main() { + a.A() + b.B() +} diff --git a/test/fixedbugs/issue32595.go b/test/fixedbugs/issue32595.go new file mode 100644 index 00000000..af6f1341 --- /dev/null +++ b/test/fixedbugs/issue32595.go @@ -0,0 +1,7 @@ +// rundir + +// Copyright 2019 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. + +package ignored diff --git a/test/fixedbugs/issue32680.go b/test/fixedbugs/issue32680.go new file mode 100644 index 00000000..27cba6bf --- /dev/null +++ b/test/fixedbugs/issue32680.go @@ -0,0 +1,23 @@ +// run -gcflags=-d=ssa/check/on + +// Copyright 2019 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. + +// As of 2019-06, bug affects/ed amd64 and s390x. + +package main + +var foo = []byte{105, 57, 172, 152} + +func main() { + for i := 0; i < len(foo); i += 4 { + // Requires inlining and non-constant i + // Note the bug/fix also apply to different widths, but was unable to reproduce for those. + println(readLittleEndian32_2(foo[i], foo[i+1], foo[i+2], foo[i+3])) + } +} + +func readLittleEndian32_2(a, b, c, d byte) uint32 { + return uint32(a) | (uint32(b) << 8) | (uint32(c) << 16) | (uint32(d) << 24) +} diff --git a/test/fixedbugs/issue32680.out b/test/fixedbugs/issue32680.out new file mode 100644 index 00000000..4d60a973 --- /dev/null +++ b/test/fixedbugs/issue32680.out @@ -0,0 +1 @@ +2561423721 diff --git a/test/fixedbugs/issue32680b.go b/test/fixedbugs/issue32680b.go new file mode 100644 index 00000000..61e53170 --- /dev/null +++ b/test/fixedbugs/issue32680b.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2019 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. + +package p + +func hashBytesRaw(b0, b1, b2, b3, b7 byte) uint64 { + return (uint64(b0) | uint64(b1)<<8 | uint64(b2)<<16 | uint64(b3)<<24) +} + +func doStuff(data []byte) uint64 { + return hashBytesRaw(data[0], data[1], data[2], data[3], data[7]) + +} diff --git a/test/fixedbugs/issue32778.dir/a.go b/test/fixedbugs/issue32778.dir/a.go new file mode 100644 index 00000000..1e6ac012 --- /dev/null +++ b/test/fixedbugs/issue32778.dir/a.go @@ -0,0 +1,18 @@ +// Copyright 2019 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. + +package a + +import "strings" + +type Name string + +type FullName string + +func (n FullName) Name() Name { + if i := strings.LastIndexByte(string(n), '.'); i >= 0 { + return Name(n[i+1:]) + } + return Name(n) +} diff --git a/test/fixedbugs/issue32778.dir/b.go b/test/fixedbugs/issue32778.dir/b.go new file mode 100644 index 00000000..a0ee398d --- /dev/null +++ b/test/fixedbugs/issue32778.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2019 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. + +package b + +import "./a" + +func Expo(fn a.FullName) a.Name { + return fn.Name() +} diff --git a/test/fixedbugs/issue32778.go b/test/fixedbugs/issue32778.go new file mode 100644 index 00000000..83456d4a --- /dev/null +++ b/test/fixedbugs/issue32778.go @@ -0,0 +1,11 @@ +// compiledir + +// Copyright 2019 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. + +// This directory contains a pair of packages that triggers a compiler +// crash in gccgo (problem with tracking indirectly referenced +// packages during exporting). See issue 32778 for details. + +package ignored diff --git a/test/fixedbugs/issue32901.dir/a.go b/test/fixedbugs/issue32901.dir/a.go new file mode 100644 index 00000000..54ed7713 --- /dev/null +++ b/test/fixedbugs/issue32901.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package a + +type T struct { x int } + +func F() interface{} { + return [2]T{} +} + +func P() interface{} { + return &[2]T{} +} diff --git a/test/fixedbugs/issue32901.dir/b.go b/test/fixedbugs/issue32901.dir/b.go new file mode 100644 index 00000000..932d7b0a --- /dev/null +++ b/test/fixedbugs/issue32901.dir/b.go @@ -0,0 +1,15 @@ +// Copyright 2019 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. + +package b + +import "./a" + +func F() interface{} { + return a.F() +} + +func P() interface{} { + return a.P() +} diff --git a/test/fixedbugs/issue32901.dir/c.go b/test/fixedbugs/issue32901.dir/c.go new file mode 100644 index 00000000..5f31c7ff --- /dev/null +++ b/test/fixedbugs/issue32901.dir/c.go @@ -0,0 +1,17 @@ +// Copyright 2019 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. + +package c + +import "./b" + +func F() interface{} { + go func(){}() // make it non-inlineable + return b.F() +} + +func P() interface{} { + go func(){}() // make it non-inlineable + return b.P() +} diff --git a/test/fixedbugs/issue32901.dir/main.go b/test/fixedbugs/issue32901.dir/main.go new file mode 100644 index 00000000..28bb8cde --- /dev/null +++ b/test/fixedbugs/issue32901.dir/main.go @@ -0,0 +1,18 @@ +// Copyright 2019 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. + +package main + +import "./c" +import "reflect" + +func main() { + x := c.F() + p := c.P() + t := reflect.PtrTo(reflect.TypeOf(x)) + tp := reflect.TypeOf(p) + if t != tp { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue32901.go b/test/fixedbugs/issue32901.go new file mode 100644 index 00000000..004c3da7 --- /dev/null +++ b/test/fixedbugs/issue32901.go @@ -0,0 +1,9 @@ +// rundir + +// Copyright 2019 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. + +// Issue 32901: type descriptor equality bug in gccgo. + +package ignored diff --git a/test/fixedbugs/issue32922.dir/a.go b/test/fixedbugs/issue32922.dir/a.go new file mode 100644 index 00000000..b13c4b40 --- /dev/null +++ b/test/fixedbugs/issue32922.dir/a.go @@ -0,0 +1,18 @@ +// Copyright 2019 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. + +package a + +func A() int { + return p("count") +} + +func p(which string, args ...string) int { + switch which { + case "count", "something": + return 1 + default: + return 2 + } +} diff --git a/test/fixedbugs/issue32922.dir/b.go b/test/fixedbugs/issue32922.dir/b.go new file mode 100644 index 00000000..fdaf42d3 --- /dev/null +++ b/test/fixedbugs/issue32922.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2019 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. + +package b + +import "./a" + +func B() int { + return 99 + a.A() +} diff --git a/test/fixedbugs/issue32922.go b/test/fixedbugs/issue32922.go new file mode 100644 index 00000000..005c8e68 --- /dev/null +++ b/test/fixedbugs/issue32922.go @@ -0,0 +1,11 @@ +// compiledir + +// Copyright 2019 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. + +// This directory contains a pair of packages that triggers a compiler +// error in gccgo (problem with the way inlinable call expressions are +// imported). See issue 32922 for details. + +package ignored diff --git a/test/fixedbugs/issue32959.go b/test/fixedbugs/issue32959.go new file mode 100644 index 00000000..a0dc789a --- /dev/null +++ b/test/fixedbugs/issue32959.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2019 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 with shifting constant + +package main + +import "unsafe" + +func main() { + var l uint64 + var p unsafe.Pointer + _ = unsafe.Pointer(uintptr(p) + (uintptr(l) >> 1)) +} diff --git a/test/fixedbugs/issue33013.dir/a.go b/test/fixedbugs/issue33013.dir/a.go new file mode 100644 index 00000000..056be88a --- /dev/null +++ b/test/fixedbugs/issue33013.dir/a.go @@ -0,0 +1,9 @@ +// Copyright 2019 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. + +package a + +type G interface { + UsesEmpty(p interface{}) int +} diff --git a/test/fixedbugs/issue33013.dir/b.go b/test/fixedbugs/issue33013.dir/b.go new file mode 100644 index 00000000..5694b582 --- /dev/null +++ b/test/fixedbugs/issue33013.dir/b.go @@ -0,0 +1,24 @@ +// Copyright 2019 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. + +package b + +import "a" + +type Service uint64 +type ServiceDesc struct { + X int + uc +} + +type uc interface { + f() a.G +} + +var q int + +func RS(svcd *ServiceDesc, server interface{}, qq uint8) *Service { + defer func() { q += int(qq) }() + return nil +} diff --git a/test/fixedbugs/issue33013.dir/c.go b/test/fixedbugs/issue33013.dir/c.go new file mode 100644 index 00000000..bfdc0b53 --- /dev/null +++ b/test/fixedbugs/issue33013.dir/c.go @@ -0,0 +1,19 @@ +// Copyright 2019 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. + +package c + +import ( + "a" + "b" +) + +type BI interface { + Something(s int64) int64 + Another(pxp a.G) int32 +} + +func BRS(sd *b.ServiceDesc, server BI, xyz int) *b.Service { + return b.RS(sd, server, 7) +} diff --git a/test/fixedbugs/issue33013.dir/d.go b/test/fixedbugs/issue33013.dir/d.go new file mode 100644 index 00000000..f4fff4ac --- /dev/null +++ b/test/fixedbugs/issue33013.dir/d.go @@ -0,0 +1,16 @@ +// Copyright 2019 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. + +package d + +import ( + "b" + "c" +) + +var GA b.Service + +func C() { + c.BRS(nil, nil, 22) +} diff --git a/test/fixedbugs/issue33013.go b/test/fixedbugs/issue33013.go new file mode 100644 index 00000000..e363cf50 --- /dev/null +++ b/test/fixedbugs/issue33013.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2019 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. + +// Issue 33013: gccgo compiler error with inlinable function + +package ignored diff --git a/test/fixedbugs/issue33020.dir/a.go b/test/fixedbugs/issue33020.dir/a.go new file mode 100644 index 00000000..948f4fdf --- /dev/null +++ b/test/fixedbugs/issue33020.dir/a.go @@ -0,0 +1,16 @@ +// Copyright 2019 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. + +package a + +var G1 int +var G2 int +var G3 int +var G4 int +var G5 int +var G6 int +var G7 int +var G8 int +var G9 int +var G10 int diff --git a/test/fixedbugs/issue33020.dir/b.go b/test/fixedbugs/issue33020.dir/b.go new file mode 100644 index 00000000..354ab3eb --- /dev/null +++ b/test/fixedbugs/issue33020.dir/b.go @@ -0,0 +1,22 @@ +// Copyright 2019 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. + +package b + +import "a" + +var N n + +type n struct{} + +func (r n) M1() int { return a.G1 } +func (r n) M2() int { return a.G2 } +func (r n) M3() int { return a.G3 } +func (r n) M4() int { return a.G4 } +func (r n) M5() int { return a.G5 } +func (r n) M6() int { return a.G6 } +func (r n) M7() int { return a.G7 } +func (r n) M8() int { return a.G8 } +func (r n) M9() int { return a.G9 } +func (r n) M10() int { return a.G10 } diff --git a/test/fixedbugs/issue33020.go b/test/fixedbugs/issue33020.go new file mode 100644 index 00000000..ccdf1874 --- /dev/null +++ b/test/fixedbugs/issue33020.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2019 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. + +// Issue 33020: gccgo undefined behavior with inlinable function + +package ignored diff --git a/test/fixedbugs/issue33062.go b/test/fixedbugs/issue33062.go new file mode 100644 index 00000000..5e6a3581 --- /dev/null +++ b/test/fixedbugs/issue33062.go @@ -0,0 +1,33 @@ +// run + +// Copyright 2019 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. + +// Issue 33062: gccgo generates incorrect type equality +// functions. + +package main + +type simpleStruct struct { + int + string +} + +type complexStruct struct { + int + simpleStruct +} + +func main() { + x := complexStruct{1, simpleStruct{2, "xxx"}} + ix := interface{}(x) + y := complexStruct{1, simpleStruct{2, "yyy"}} + iy := interface{}(y) + if ix != ix { + panic("FAIL") + } + if ix == iy { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue33158.dir/a.go b/test/fixedbugs/issue33158.dir/a.go new file mode 100644 index 00000000..28714e0c --- /dev/null +++ b/test/fixedbugs/issue33158.dir/a.go @@ -0,0 +1,25 @@ +// Copyright 2019 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. + +package a + +var GS string + +func M() string { + if s := getname("Fred"); s != "" { + return s + } + if s := getname("Joe"); s != "" { + return s + } + + return string("Alex") +} + +// getname can be any function returning a string, just has to be non-inlinable. + +//go:noinline +func getname(s string) string { + return s + "foo" +} diff --git a/test/fixedbugs/issue33158.dir/b.go b/test/fixedbugs/issue33158.dir/b.go new file mode 100644 index 00000000..a16f0da6 --- /dev/null +++ b/test/fixedbugs/issue33158.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2019 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. + +package b + +import "a" + +func B() string { + return a.M() +} diff --git a/test/fixedbugs/issue33158.go b/test/fixedbugs/issue33158.go new file mode 100644 index 00000000..1bba8f2f --- /dev/null +++ b/test/fixedbugs/issue33158.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2019 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. + +// Issue 33158: gccgo duplicate def error from importing inlinable function + +package ignored diff --git a/test/fixedbugs/issue33219.dir/a.go b/test/fixedbugs/issue33219.dir/a.go new file mode 100644 index 00000000..2d96301f --- /dev/null +++ b/test/fixedbugs/issue33219.dir/a.go @@ -0,0 +1,17 @@ +// Copyright 2019 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. + +package a + +type A interface { + M(i interface{}) interface{} +} + +var a1 A +var a2 A + +func V(p A, k, v interface{}) A { + defer func() { a1, a2 = a2, a1 }() + return a1 +} diff --git a/test/fixedbugs/issue33219.dir/b.go b/test/fixedbugs/issue33219.dir/b.go new file mode 100644 index 00000000..2a8f518b --- /dev/null +++ b/test/fixedbugs/issue33219.dir/b.go @@ -0,0 +1,25 @@ +// Copyright 2019 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. + +package b + +import "./a" + +type Service uint64 + +var q *Service +var r *Service + +type f struct{} + +var fk f + +func No(s a.A, qq uint8) *Service { + defer func() { q, r = r, q }() + return q +} + +func Yes(s a.A, p *uint64) a.A { + return a.V(s, fk, p) +} diff --git a/test/fixedbugs/issue33219.dir/c.go b/test/fixedbugs/issue33219.dir/c.go new file mode 100644 index 00000000..ece48d76 --- /dev/null +++ b/test/fixedbugs/issue33219.dir/c.go @@ -0,0 +1,20 @@ +// Copyright 2019 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. + +package c + +import ( + "a" + "b" +) + +type BI interface { + Another(pxp a.A) int32 +} + +//go:noinline +func BRS(sd a.A, xyz int) *b.Service { + x := b.Yes(sd, nil) + return b.No(x, 1) +} diff --git a/test/fixedbugs/issue33219.go b/test/fixedbugs/issue33219.go new file mode 100644 index 00000000..45edc8ba --- /dev/null +++ b/test/fixedbugs/issue33219.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2019 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. + +// Issue 33219: gccgo assert in "implements_interface()" + +package ignored diff --git a/test/fixedbugs/issue33355.go b/test/fixedbugs/issue33355.go new file mode 100644 index 00000000..c4b1e2e1 --- /dev/null +++ b/test/fixedbugs/issue33355.go @@ -0,0 +1,147 @@ +// compile + +// Copyright 2019 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. + +// This code failed on arm64 in the register allocator. +// See issue 33355. + +package server + +import ( + "bytes" + "sync" +) + +type client struct { + junk [4]int + mu sync.Mutex + srv *Server + gw *gateway + msgb [100]byte +} + +type gateway struct { + cfg *gatewayCfg + outsim *sync.Map +} + +type gatewayCfg struct { + replyPfx []byte +} + +type Account struct { + Name string +} + +type Server struct { + gateway *srvGateway +} + +type srvGateway struct { + outo []*client +} + +type subscription struct { + queue []byte + client *client +} + +type outsie struct { + ni map[string]struct{} + sl *Sublist + qsubs int +} + +type Sublist struct { +} + +type SublistResult struct { + psubs []*subscription + qsubs [][]*subscription +} + +var subPool = &sync.Pool{} + +func (c *client) sendMsgToGateways(acc *Account, msg, subject, reply []byte, qgroups [][]byte) { + var gws []*client + gw := c.srv.gateway + for i := 0; i < len(gw.outo); i++ { + gws = append(gws, gw.outo[i]) + } + var ( + subj = string(subject) + queuesa = [512]byte{} + queues = queuesa[:0] + mreply []byte + dstPfx []byte + checkReply = len(reply) > 0 + ) + + sub := subPool.Get().(*subscription) + + if subjectStartsWithGatewayReplyPrefix(subject) { + dstPfx = subject[:8] + } + for i := 0; i < len(gws); i++ { + gwc := gws[i] + if dstPfx != nil { + gwc.mu.Lock() + ok := bytes.Equal(dstPfx, gwc.gw.cfg.replyPfx) + gwc.mu.Unlock() + if !ok { + continue + } + } else { + qr := gwc.gatewayInterest(acc.Name, subj) + queues = queuesa[:0] + for i := 0; i < len(qr.qsubs); i++ { + qsubs := qr.qsubs[i] + queue := qsubs[0].queue + add := true + for _, qn := range qgroups { + if bytes.Equal(queue, qn) { + add = false + break + } + } + if add { + qgroups = append(qgroups, queue) + } + } + if len(queues) == 0 { + continue + } + } + if checkReply { + checkReply = false + mreply = reply + } + mh := c.msgb[:10] + mh = append(mh, subject...) + if len(queues) > 0 { + mh = append(mh, mreply...) + mh = append(mh, queues...) + } + sub.client = gwc + } + subPool.Put(sub) +} + +func subjectStartsWithGatewayReplyPrefix(subj []byte) bool { + return len(subj) > 8 && string(subj[:4]) == "foob" +} + +func (c *client) gatewayInterest(acc, subj string) *SublistResult { + ei, _ := c.gw.outsim.Load(acc) + var r *SublistResult + e := ei.(*outsie) + r = e.sl.Match(subj) + return r +} + +func (s *Sublist) Match(subject string) *SublistResult { + return nil +} + diff --git a/test/fixedbugs/issue33438.go b/test/fixedbugs/issue33438.go new file mode 100644 index 00000000..e4206d7b --- /dev/null +++ b/test/fixedbugs/issue33438.go @@ -0,0 +1,19 @@ +// compile + +// Copyright 2019 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. + +package p + +type hasPtrs struct { + x [2]*int + // Note: array size needs to be >1 to force this type to be not SSAable. + // The bug triggers only for OpMove, which is only used for unSSAable types. +} + +func main() { + var x *hasPtrs // Can be local, global, or arg; nil or non-nil. + var y *hasPtrs = nil // Must initialize to nil. + *x = *y +} diff --git a/test/fixedbugs/issue33555.go b/test/fixedbugs/issue33555.go new file mode 100644 index 00000000..7debd204 --- /dev/null +++ b/test/fixedbugs/issue33555.go @@ -0,0 +1,81 @@ +// +build !nacl,!js +// run + +// Copyright 2019 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 that the linker permits long call sequences. +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" +) + +const start = ` +package main + +func main() { + println(f0() + 1) +} +` + +const fn = ` +//go:noinline +func f%d() int { + return f%d() + 1 +}` + +const fnlast = ` +//go:noinline +func f%d() int { + return 0 +} +` + +const count = 400 + +func main() { + if err := test(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func test() error { + var buf bytes.Buffer + buf.WriteString(start) + for i := 0; i < count; i++ { + fmt.Fprintf(&buf, fn, i, i + 1) + } + fmt.Fprintf(&buf, fnlast, count) + + dir, err := ioutil.TempDir("", "issue33555") + if err != nil { + return err + } + defer os.RemoveAll(dir) + + fn := filepath.Join(dir, "x.go") + if err := ioutil.WriteFile(fn, buf.Bytes(), 0644); err != nil { + return err + } + + out, err := exec.Command("go", "run", fn).CombinedOutput() + if err != nil { + return err + } + + want := strconv.Itoa(count + 1) + if got := string(bytes.TrimSpace(out)); got != want { + return fmt.Errorf("got %q want %q", got, want) + } + + return nil +} diff --git a/test/fixedbugs/issue4099.go b/test/fixedbugs/issue4099.go index 8ea809c2..5a4ea7c9 100644 --- a/test/fixedbugs/issue4099.go +++ b/test/fixedbugs/issue4099.go @@ -19,8 +19,8 @@ func F2([]byte) func G() { var buf1 [10]byte - F1(buf1[:]) // ERROR "buf1 does not escape" + F1(buf1[:]) var buf2 [10]byte // ERROR "moved to heap: buf2" - F2(buf2[:]) // ERROR "buf2 escapes to heap" + F2(buf2[:]) } diff --git a/test/fixedbugs/issue7921.go b/test/fixedbugs/issue7921.go index ce8d09a2..e19b1130 100644 --- a/test/fixedbugs/issue7921.go +++ b/test/fixedbugs/issue7921.go @@ -17,9 +17,9 @@ func bufferNotEscape() string { // copied during String() call, but object "handle" itself // can be stack-allocated. var b bytes.Buffer - b.WriteString("123") // ERROR "bufferNotEscape b does not escape$" - b.Write([]byte{'4'}) // ERROR "bufferNotEscape \[\]byte literal does not escape$" "bufferNotEscape b does not escape$" - return b.String() // ERROR "bufferNotEscape b does not escape$" "inlining call to bytes.\(\*Buffer\).String$" "string\(bytes.b.buf\[bytes.b.off:\]\) escapes to heap$" + b.WriteString("123") + b.Write([]byte{'4'}) // ERROR "bufferNotEscape \[\]byte literal does not escape$" + return b.String() // ERROR "inlining call to bytes.\(\*Buffer\).String$" "string\(bytes.b.buf\[bytes.b.off:\]\) escapes to heap$" } func bufferNoEscape2(xs []string) int { // ERROR "bufferNoEscape2 xs does not escape$" @@ -41,9 +41,9 @@ func bufferNoEscape3(xs []string) string { // ERROR "bufferNoEscape3 xs does not func bufferNoEscape4() []byte { var b bytes.Buffer - b.Grow(64) // ERROR "bufferNoEscape4 b does not escape$" "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m·3\]$" "inlining call to bytes.\(\*Buffer\).Grow$" - useBuffer(&b) // ERROR "bufferNoEscape4 &b does not escape$" - return b.Bytes() // ERROR "bufferNoEscape4 b does not escape$" "inlining call to bytes.\(\*Buffer\).Bytes$" + b.Grow(64) // ERROR "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m·3\]$" "inlining call to bytes.\(\*Buffer\).Grow$" + useBuffer(&b) + return b.Bytes() // ERROR "inlining call to bytes.\(\*Buffer\).Bytes$" } func bufferNoEscape5() { // ERROR "can inline bufferNoEscape5$" diff --git a/test/fixedbugs/issue8183.go b/test/fixedbugs/issue8183.go index f23e660e..531dd4db 100644 --- a/test/fixedbugs/issue8183.go +++ b/test/fixedbugs/issue8183.go @@ -18,6 +18,6 @@ const ( const ( c = len([1 - iota]int{}) d - e // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant" - f // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant" + e // ERROR "array bound must be non-negative" + f // ERROR "array bound must be non-negative" ) diff --git a/test/fixedbugs/issue9036.go b/test/fixedbugs/issue9036.go index 75ffb2dd..38f06c30 100644 --- a/test/fixedbugs/issue9036.go +++ b/test/fixedbugs/issue9036.go @@ -4,7 +4,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Expects to see error messages on 'p' exponents. +// Expects to see error messages on 'p' exponents +// for non-hexadecimal floats. package main @@ -16,16 +17,9 @@ const ( x3 = 0x1e10 // integer (e is a hex digit) ) -// 'p' exponents are invalid - the 'p' is not considered -// part of a floating-point number, but introduces a new -// (unexpected) name. -// -// Error recovery is not ideal and we use a new declaration -// each time for the parser to recover. - -const x4 = 0x1p10 // ERROR "unexpected p10" -const x5 = 1p10 // ERROR "unexpected p10" -const x6 = 0p0 // ERROR "unexpected p0" +const x4 = 0x1p10 // valid hexadecimal float +const x5 = 1p10 // ERROR "'p' exponent requires hexadecimal mantissa" +const x6 = 0P0 // ERROR "'P' exponent requires hexadecimal mantissa" func main() { fmt.Printf("%g %T\n", x1, x1) diff --git a/test/fixedbugs/issue9521.go b/test/fixedbugs/issue9521.go index ef0a5a65..4e4a55f1 100644 --- a/test/fixedbugs/issue9521.go +++ b/test/fixedbugs/issue9521.go @@ -13,6 +13,6 @@ func f() (_, _ []int) { return } func g() (x []int, y float64) { return } func main() { - _ = append(f()) // ERROR "cannot append \[\]int value to \[\]int" - _ = append(g()) // ERROR "cannot append float64 value to \[\]int" + _ = append(f()) // ERROR "cannot use \[\]int value as type int in append" + _ = append(g()) // ERROR "cannot use float64 value as type int in append" } diff --git a/test/fixedbugs/oldescape_issue12006.go b/test/fixedbugs/oldescape_issue12006.go new file mode 100644 index 00000000..0697f58b --- /dev/null +++ b/test/fixedbugs/oldescape_issue12006.go @@ -0,0 +1,174 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 through ... parameters. + +package foo + +func FooN(vals ...*int) (s int) { // ERROR "FooN vals does not escape" + for _, v := range vals { + s += *v + } + return s +} + +// Append forces heap allocation and copies entries in vals to heap, therefore they escape to heap. +func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param content: vals" + vals = append(vals, x) + return FooN(vals...) +} + +var sink []*int + +func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" "leaking param content: vals" + vals = append(vals, x) + sink = vals + return FooN(vals...) +} + +func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals" + sink = vals + return FooN(vals...) +} + +func TFooN() { + for i := 0; i < 1000; i++ { + var i, j int + FooN(&i, &j) // ERROR "TFooN ... argument does not escape" + } +} + +func TFooNx() { + for i := 0; i < 1000; i++ { + var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" + FooNx(&k, &i, &j) // ERROR "TFooNx ... argument does not escape" + } +} + +func TFooNy() { + for i := 0; i < 1000; i++ { + var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" + FooNy(&k, &i, &j) // ERROR "... argument escapes to heap" + } +} + +func TFooNz() { + for i := 0; i < 1000; i++ { + var i, j int // ERROR "moved to heap: i" "moved to heap: j" + FooNz(&i, &j) // ERROR "... argument escapes to heap" + } +} + +var isink *int32 + +func FooI(args ...interface{}) { // ERROR "leaking param content: args" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + isink = x + case string: + println("is string") + } + } +} + +func TFooI() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooI ... argument does not escape" +} + +func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooJ1() { + a := int32(1) + b := "cat" + c := &a + FooJ(a, b, c) // ERROR "TFooJ1 a does not escape" "TFooJ1 b does not escape" "TFooJ1 c does not escape" "TFooJ1 ... argument does not escape" +} + +func TFooJ2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooJ2 ... argument does not escape" +} + +type fakeSlice struct { + l int + a *[4]interface{} +} + +func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < args.l; i++ { + switch x := (*args.a)[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooK2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooK2 &\[4\]interface {} literal does not escape" + isink = FooK(fs) +} + +func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" + for i := 0; i < len(args); i++ { + switch x := args[i].(type) { + case nil: + println("is nil") + case int32: + println("is int32") + case *int32: + println("is *int32") + return x + case string: + println("is string") + } + } + return nil +} + +func TFooL2() { + a := int32(1) // ERROR "moved to heap: a" + b := "cat" + c := &a + s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooL2 \[\]interface {} literal does not escape" + isink = FooL(s) +} diff --git a/test/fixedbugs/oldescape_issue17318.go b/test/fixedbugs/oldescape_issue17318.go new file mode 100644 index 00000000..10084ba8 --- /dev/null +++ b/test/fixedbugs/oldescape_issue17318.go @@ -0,0 +1,47 @@ +// errorcheck -0 -N -m -l -newescape=false + +// Copyright 2016 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. + +// The escape analyzer needs to run till its root set settles +// (this is not that often, it turns out). +// This test is likely to become stale because the leak depends +// on a spurious-escape bug -- return an interface as a named +// output parameter appears to cause the called closure to escape, +// where returning it as a regular type does not. + +package main + +import ( + "fmt" +) + +type closure func(i, j int) ent + +type ent int + +func (e ent) String() string { + return fmt.Sprintf("%d", int(e)) // ERROR "ent.String ... argument does not escape$" "int\(e\) escapes to heap$" +} + +//go:noinline +func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$" + enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$" + return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" + } + err = enqueue(4) + if err != nil { + return err + } + return // return result of enqueue, a fmt.Stringer +} + +func main() { + // 3 identical functions, to get different escape behavior. + f := func(i, j int) ent { // ERROR "func literal escapes to heap$" + return ent(i + j) + } + i := foo(f, 3).(ent) + fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "main ... argument does not escape$" +} diff --git a/test/heapsampling.go b/test/heapsampling.go index c00b8666..cc72832a 100644 --- a/test/heapsampling.go +++ b/test/heapsampling.go @@ -18,38 +18,113 @@ var a16 *[16]byte var a512 *[512]byte var a256 *[256]byte var a1k *[1024]byte -var a64k *[64 * 1024]byte +var a16k *[16 * 1024]byte +var a17k *[17 * 1024]byte +var a18k *[18 * 1024]byte -// This test checks that heap sampling produces reasonable -// results. Note that heap sampling uses randomization, so the results -// vary for run to run. This test only checks that the resulting -// values appear reasonable. +// This test checks that heap sampling produces reasonable results. +// Note that heap sampling uses randomization, so the results vary for +// run to run. To avoid flakes, this test performs multiple +// experiments and only complains if all of them consistently fail. func main() { - const countInterleaved = 10000 - allocInterleaved(countInterleaved) - checkAllocations(getMemProfileRecords(), "main.allocInterleaved", countInterleaved, []int64{256 * 1024, 1024, 256 * 1024, 512, 256 * 1024, 256}) + // Sample at 16K instead of default 512K to exercise sampling more heavily. + runtime.MemProfileRate = 16 * 1024 - const count = 100000 - alloc(count) - checkAllocations(getMemProfileRecords(), "main.alloc", count, []int64{1024, 512, 256}) + if err := testInterleavedAllocations(); err != nil { + panic(err.Error()) + } + if err := testSmallAllocations(); err != nil { + panic(err.Error()) + } +} + +// Repeatedly exercise a set of allocations and check that the heap +// profile collected by the runtime unsamples to a reasonable +// value. Because sampling is based on randomization, there can be +// significant variability on the unsampled data. To account for that, +// the testcase allows for a 10% margin of error, but only fails if it +// consistently fails across three experiments, avoiding flakes. +func testInterleavedAllocations() error { + const iters = 100000 + // Sizes of the allocations performed by each experiment. + frames := []string{"main.allocInterleaved1", "main.allocInterleaved2", "main.allocInterleaved3"} + + // Pass if at least one of three experiments has no errors. Use a separate + // function for each experiment to identify each experiment in the profile. + allocInterleaved1(iters) + if checkAllocations(getMemProfileRecords(), frames[0:1], iters, allocInterleavedSizes) == nil { + // Passed on first try, report no error. + return nil + } + allocInterleaved2(iters) + if checkAllocations(getMemProfileRecords(), frames[0:2], iters, allocInterleavedSizes) == nil { + // Passed on second try, report no error. + return nil + } + allocInterleaved3(iters) + // If it fails a third time, we may be onto something. + return checkAllocations(getMemProfileRecords(), frames[0:3], iters, allocInterleavedSizes) } -// allocInterleaved stress-tests the heap sampling logic by -// interleaving large and small allocations. +var allocInterleavedSizes = []int64{17 * 1024, 1024, 18 * 1024, 512, 16 * 1024, 256} + +// allocInterleaved stress-tests the heap sampling logic by interleaving large and small allocations. func allocInterleaved(n int) { for i := 0; i < n; i++ { // Test verification depends on these lines being contiguous. - a64k = new([64 * 1024]byte) + a17k = new([17 * 1024]byte) a1k = new([1024]byte) - a64k = new([64 * 1024]byte) + a18k = new([18 * 1024]byte) a512 = new([512]byte) - a64k = new([64 * 1024]byte) + a16k = new([16 * 1024]byte) a256 = new([256]byte) + // Test verification depends on these lines being contiguous. + } +} + +func allocInterleaved1(n int) { + allocInterleaved(n) +} + +func allocInterleaved2(n int) { + allocInterleaved(n) +} + +func allocInterleaved3(n int) { + allocInterleaved(n) +} + +// Repeatedly exercise a set of allocations and check that the heap +// profile collected by the runtime unsamples to a reasonable +// value. Because sampling is based on randomization, there can be +// significant variability on the unsampled data. To account for that, +// the testcase allows for a 10% margin of error, but only fails if it +// consistently fails across three experiments, avoiding flakes. +func testSmallAllocations() error { + const iters = 100000 + // Sizes of the allocations performed by each experiment. + sizes := []int64{1024, 512, 256} + frames := []string{"main.allocSmall1", "main.allocSmall2", "main.allocSmall3"} + + // Pass if at least one of three experiments has no errors. Use a separate + // function for each experiment to identify each experiment in the profile. + allocSmall1(iters) + if checkAllocations(getMemProfileRecords(), frames[0:1], iters, sizes) == nil { + // Passed on first try, report no error. + return nil + } + allocSmall2(iters) + if checkAllocations(getMemProfileRecords(), frames[0:2], iters, sizes) == nil { + // Passed on second try, report no error. + return nil } + allocSmall3(iters) + // If it fails a third time, we may be onto something. + return checkAllocations(getMemProfileRecords(), frames[0:3], iters, sizes) } -// alloc performs only small allocations for sanity testing. -func alloc(n int) { +// allocSmall performs only small allocations for sanity testing. +func allocSmall(n int) { for i := 0; i < n; i++ { // Test verification depends on these lines being contiguous. a1k = new([1024]byte) @@ -58,36 +133,86 @@ func alloc(n int) { } } +// Three separate instances of testing to avoid flakes. Will report an error +// only if they all consistently report failures. +func allocSmall1(n int) { + allocSmall(n) +} + +func allocSmall2(n int) { + allocSmall(n) +} + +func allocSmall3(n int) { + allocSmall(n) +} + // checkAllocations validates that the profile records collected for // the named function are consistent with count contiguous allocations // of the specified sizes. -func checkAllocations(records []runtime.MemProfileRecord, fname string, count int64, size []int64) { - a := allocObjects(records, fname) - firstLine := 0 - for ln := range a { +// Check multiple functions and only report consistent failures across +// multiple tests. +// Look only at samples that include the named frames, and group the +// allocations by their line number. All these allocations are done from +// the same leaf function, so their line numbers are the same. +func checkAllocations(records []runtime.MemProfileRecord, frames []string, count int64, size []int64) error { + objectsPerLine := map[int][]int64{} + bytesPerLine := map[int][]int64{} + totalCount := []int64{} + // Compute the line number of the first allocation. All the + // allocations are from the same leaf, so pick the first one. + var firstLine int + for ln := range allocObjects(records, frames[0]) { if firstLine == 0 || firstLine > ln { firstLine = ln } } - var totalcount int64 + for _, frame := range frames { + var objectCount int64 + a := allocObjects(records, frame) + for s := range size { + // Allocations of size size[s] should be on line firstLine + s. + ln := firstLine + s + objectsPerLine[ln] = append(objectsPerLine[ln], a[ln].objects) + bytesPerLine[ln] = append(bytesPerLine[ln], a[ln].bytes) + objectCount += a[ln].objects + } + totalCount = append(totalCount, objectCount) + } for i, w := range size { ln := firstLine + i - s := a[ln] - checkValue(fname, ln, "objects", count, s.objects) - checkValue(fname, ln, "bytes", count*w, s.bytes) - totalcount += s.objects - } - // Check the total number of allocations, to ensure some sampling occurred. - if totalwant := count * int64(len(size)); totalcount <= 0 || totalcount > totalwant*1024 { - panic(fmt.Sprintf("%s want total count > 0 && <= %d, got %d", fname, totalwant*1024, totalcount)) + if err := checkValue(frames[0], ln, "objects", count, objectsPerLine[ln]); err != nil { + return err + } + if err := checkValue(frames[0], ln, "bytes", count*w, bytesPerLine[ln]); err != nil { + return err + } } + return checkValue(frames[0], 0, "total", count*int64(len(size)), totalCount) } -// checkValue checks an unsampled value against a range. -func checkValue(fname string, ln int, name string, want, got int64) { - if got < 0 || got > 1024*want { - panic(fmt.Sprintf("%s:%d want %s >= 0 && <= %d, got %d", fname, ln, name, 1024*want, got)) +// checkValue checks an unsampled value against its expected value. +// Given that this is a sampled value, it will be unexact and will change +// from run to run. Only report it as a failure if all the values land +// consistently far from the expected value. +func checkValue(fname string, ln int, testName string, want int64, got []int64) error { + if got == nil { + return fmt.Errorf("Unexpected empty result") + } + min, max := got[0], got[0] + for _, g := range got[1:] { + if g < min { + min = g + } + if g > max { + max = g + } + } + margin := want / 10 // 10% margin. + if min > want+margin || max < want-margin { + return fmt.Errorf("%s:%d want %s in [%d: %d], got %v", fname, ln, testName, want-margin, want+margin, got) } + return nil } func getMemProfileRecords() []runtime.MemProfileRecord { @@ -124,24 +249,35 @@ type allocStat struct { bytes, objects int64 } -// allocObjects examines the profile records for the named function -// and returns the allocation stats aggregated by source line number. +// allocObjects examines the profile records for samples including the +// named function and returns the allocation stats aggregated by +// source line number of the allocation (at the leaf frame). func allocObjects(records []runtime.MemProfileRecord, function string) map[int]allocStat { a := make(map[int]allocStat) for _, r := range records { + var pcs []uintptr for _, s := range r.Stack0 { if s == 0 { break } - if f := runtime.FuncForPC(s); f != nil { - name := f.Name() - _, line := f.FileLine(s) - if name == function { - allocStat := a[line] - allocStat.bytes += r.AllocBytes - allocStat.objects += r.AllocObjects - a[line] = allocStat - } + pcs = append(pcs, s) + } + frames := runtime.CallersFrames(pcs) + line := 0 + for { + frame, more := frames.Next() + name := frame.Function + if line == 0 { + line = frame.Line + } + if name == function { + allocStat := a[line] + allocStat.bytes += r.AllocBytes + allocStat.objects += r.AllocObjects + a[line] = allocStat + } + if !more { + break } } } diff --git a/test/init.go b/test/init.go index f4689443..317f2472 100644 --- a/test/init.go +++ b/test/init.go @@ -9,13 +9,11 @@ package main -import "runtime" - func init() { } func main() { init() // ERROR "undefined.*init" - runtime.init() // ERROR "unexported.*runtime\.init" + runtime.init() // ERROR "undefined.*runtime\.init" var _ = init // ERROR "undefined.*init" } diff --git a/test/inline.go b/test/inline.go index 9428c148..7e055170 100644 --- a/test/inline.go +++ b/test/inline.go @@ -74,7 +74,7 @@ func m() int { // address taking prevents closure inlining func n() int { foo := func() int { return 1 } // ERROR "can inline n.func1" "func literal does not escape" - bar := &foo // ERROR "&foo does not escape" + bar := &foo x := (*bar)() + foo() return x } @@ -115,7 +115,7 @@ func s0(x int) int { foo := func() { // ERROR "can inline s0.func1" "s0 func literal does not escape" x = x + 1 } - foo() // ERROR "inlining call to s0.func1" "&x does not escape" + foo() // ERROR "inlining call to s0.func1" return x } @@ -124,7 +124,7 @@ func s1(x int) int { return x } x = x + 1 - return foo() // ERROR "inlining call to s1.func1" "&x does not escape" + return foo() // ERROR "inlining call to s1.func1" } // can't currently inline functions with a break statement diff --git a/test/inline_sync.go b/test/inline_sync.go new file mode 100644 index 00000000..30b436af --- /dev/null +++ b/test/inline_sync.go @@ -0,0 +1,53 @@ +// +build !nacl,!386,!wasm,!arm,!gcflags_noopt +// errorcheck -0 -m + +// Copyright 2019 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, using compiler diagnostic flags, that inlining of functions +// imported from the sync package is working. +// Compiles but does not run. + +// FIXME: This test is disabled on architectures where atomic operations +// are function calls rather than intrinsics, since this prevents inlining +// of the sync fast paths. This test should be re-enabled once the problem +// is solved. + +package foo + +import ( + "sync" +) + +var mutex *sync.Mutex + +func small5() { // ERROR "can inline small5" + // the Unlock fast path should be inlined + mutex.Unlock() // ERROR "inlining call to sync\.\(\*Mutex\)\.Unlock" +} + +func small6() { // ERROR "can inline small6" + // the Lock fast path should be inlined + mutex.Lock() // ERROR "inlining call to sync\.\(\*Mutex\)\.Lock" +} + +var once *sync.Once + +func small7() { // ERROR "can inline small7" + // the Do fast path should be inlined + once.Do(small5) // ERROR "inlining call to sync\.\(\*Once\)\.Do" +} + +var rwmutex *sync.RWMutex + +func small8() { // ERROR "can inline small8" + // the RUnlock fast path should be inlined + rwmutex.RUnlock() // ERROR "inlining call to sync\.\(\*RWMutex\)\.RUnlock" +} + +func small9() { // ERROR "can inline small9" + // the RLock fast path should be inlined + rwmutex.RLock() // ERROR "inlining call to sync\.\(\*RWMutex\)\.RLock" +} + diff --git a/test/linkname.dir/linkname2.go b/test/linkname.dir/linkname2.go index 5df4f50f..9323ac5f 100644 --- a/test/linkname.dir/linkname2.go +++ b/test/linkname.dir/linkname2.go @@ -3,7 +3,7 @@ package y import _ "unsafe" //go:linkname byteIndex linkname1.indexByte -func byteIndex(xs []byte, b byte) int +func byteIndex(xs []byte, b byte) int // ERROR "leaking param: xs" func ContainsSlash(data []byte) bool { // ERROR "leaking param: data" "can inline ContainsSlash" if byteIndex(data, '/') != -1 { diff --git a/test/linkname.go b/test/linkname.go index c94a113c..8e79b51b 100644 --- a/test/linkname.go +++ b/test/linkname.go @@ -1,4 +1,4 @@ -// errorcheckandrundir -0 -m -l=4 +// errorcheckandrundir -0 -m -l=4 -newescape=true // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/literal2.go b/test/literal2.go new file mode 100644 index 00000000..f552e33a --- /dev/null +++ b/test/literal2.go @@ -0,0 +1,90 @@ +// run + +// Copyright 2019 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 Go2 literal syntax for basic types. +// Avoid running gofmt on this file to preserve the +// test cases with upper-case prefixes (0B, 0O, 0X). + +package main + +import "fmt" + +func assert(cond bool) { + if !cond { + panic("assertion failed") + } +} + +func equal(x, y interface{}) bool { + if x != y { + fmt.Printf("%g != %g\n", x, y) + return false + } + return true +} + +func main() { + // 0-octals + assert(0_1 == 01) + assert(012 == 012) + assert(0_1_2 == 012) + assert(0_1_2i == complex(0, 12)) // decimal digits despite leading 0 for backward-compatibility + assert(00089i == complex(0, 89)) // decimal digits despite leading 0 for backward-compatibility + + // decimals + assert(1_000_000 == 1000000) + assert(1_000i == complex(0, 1000)) + + // hexadecimals + assert(0x_1 == 0x1) + assert(0x1_2 == 0x12) + assert(0x_cafe_f00d == 0xcafef00d) + assert(0x_cafei == complex(0, 0xcafe)) + + // octals + assert(0o_1 == 01) + assert(0o12 == 012) + assert(0o_1_2 == 012) + assert(0o_1_2i == complex(0, 0o12)) + + // binaries + assert(0b_1 == 1) + assert(0b10 == 2) + assert(0b_1_0 == 2) + assert(0b_1_0i == complex(0, 2)) + + // decimal floats + assert(0. == 0.0) + assert(.0 == 0.0) + assert(1_0. == 10.0) + assert(.0_1 == 0.01) + assert(1_0.0_1 == 10.01) + assert(1_0.0_1i == complex(0, 10.01)) + + assert(0.e1_0 == 0.0e10) + assert(.0e1_0 == 0.0e10) + assert(1_0.e1_0 == 10.0e10) + assert(.0_1e1_0 == 0.01e10) + assert(1_0.0_1e1_0 == 10.01e10) + assert(1_0.0_1e1_0i == complex(0, 10.01e10)) + + // hexadecimal floats + assert(equal(0x1p-2, 0.25)) + assert(equal(0x2.p10, 2048.0)) + assert(equal(0x1.Fp+0, 1.9375)) + assert(equal(0x.8p-0, 0.5)) + assert(equal(0x1FFFp-16, 0.1249847412109375)) + assert(equal(0x1.fffffffffffffp1023, 1.7976931348623157e308)) + assert(equal(0x1.fffffffffffffp1023i, complex(0, 1.7976931348623157e308))) + + assert(equal(0x_1p-2, 0.25)) + assert(equal(0x2.p1_0, 2048.0)) + assert(equal(0x1_0.Fp+0, 16.9375)) + assert(equal(0x_0.8p-0, 0.5)) + assert(equal(0x_1FF_Fp-16, 0.1249847412109375)) + assert(equal(0x1.f_ffff_ffff_ffffp1_023, 1.7976931348623157e308)) + assert(equal(0x1.f_ffff_ffff_ffffp1_023i, complex(0, 1.7976931348623157e308))) +} diff --git a/test/live.go b/test/live.go index e7134eca..ec511937 100644 --- a/test/live.go +++ b/test/live.go @@ -687,7 +687,7 @@ type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "li // In particular, at printint r must be live. func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$" r = p - defer func() { // ERROR "live at call to deferproc: q r$" "live at call to deferreturn: r$" + defer func() { // ERROR "live at call to deferprocStack: q r$" "live at call to deferreturn: r$" recover() }() printint(0) // ERROR "live at call to printint: q r$" diff --git a/test/live_syscall.go b/test/live_syscall.go index 7b447173..2d1ef14d 100644 --- a/test/live_syscall.go +++ b/test/live_syscall.go @@ -19,22 +19,22 @@ func f(uintptr) // ERROR "f assuming arg#1 is unsafe uintptr" func g() { // ERROR "can inline g" var t int - f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: .?autotmp" "g &t does not escape" "stack object .autotmp_[0-9]+ unsafe.Pointer$" + f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } func h() { // ERROR "can inline h" var v int - syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: .?autotmp" "h &v does not escape" "stack object .autotmp_[0-9]+ unsafe.Pointer$" + syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } func i() { // ERROR "can inline i" var t int - p := unsafe.Pointer(&t) // ERROR "i &t does not escape" + p := unsafe.Pointer(&t) f(uintptr(p)) // ERROR "live at call to f: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } func j() { // ERROR "can inline j" var v int - p := unsafe.Pointer(&v) // ERROR "j &v does not escape" + p := unsafe.Pointer(&v) syscall.Syscall(0, 1, uintptr(p), 2) // ERROR "live at call to Syscall: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } diff --git a/test/loopbce.go b/test/loopbce.go index 81f2524e..e0a6463c 100644 --- a/test/loopbce.go +++ b/test/loopbce.go @@ -63,7 +63,7 @@ func f5(a [10]int) int { func f6(a []int) { for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$" - b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" "(\([0-9]+\) )?Proved Geq64$" + b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" f6(b) } } @@ -186,10 +186,10 @@ func k0(a [100]int) [100]int { func k1(a [100]int) [100]int { for i := 10; i < 90; i++ { // ERROR "Induction variable: limits \[10,90\), increment 1$" - useSlice(a[:i-11]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" + useSlice(a[:i-11]) useSlice(a[:i-10]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" useSlice(a[:i-5]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" - useSlice(a[:i]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" "(\([0-9]+\) )?Proved Geq64$" + useSlice(a[:i]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" useSlice(a[:i+5]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" useSlice(a[:i+10]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" useSlice(a[:i+11]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$" diff --git a/test/nilptr2.go b/test/nilptr2.go index a5c03699..8a85b6db 100644 --- a/test/nilptr2.go +++ b/test/nilptr2.go @@ -35,7 +35,10 @@ var m *M var m1 *M1 var m2 *M2 -func use(interface{}) { +var V interface{} + +func use(x interface{}) { + V = x } var tests = []struct{ diff --git a/test/nosplit.go b/test/nosplit.go index 734f456c..266e6077 100644 --- a/test/nosplit.go +++ b/test/nosplit.go @@ -217,6 +217,11 @@ func main() { return } defer os.RemoveAll(dir) + os.Setenv("GOPATH", filepath.Join(dir, "_gopath")) + + if err := ioutil.WriteFile(filepath.Join(dir, "go.mod"), []byte("module go-test-nosplit\n"), 0666); err != nil { + log.Panic(err) + } tests = strings.Replace(tests, "\t", " ", -1) tests = commentRE.ReplaceAllString(tests, "") diff --git a/test/oldescape2.go b/test/oldescape2.go new file mode 100644 index 00000000..864a9561 --- /dev/null +++ b/test/oldescape2.go @@ -0,0 +1,1847 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2010 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, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. + +// escape2n.go contains all the same tests but compiles with -N. + +package foo + +import ( + "fmt" + "unsafe" +) + +var gxx *int + +func foo1(x int) { // ERROR "moved to heap: x$" + gxx = &x +} + +func foo2(yy *int) { // ERROR "leaking param: yy$" + gxx = yy +} + +func foo3(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +type T *T + +func foo3b(t T) { // ERROR "leaking param: t$" + *t = t +} + +// xx isn't going anywhere, so use of yy is ok +func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" + xx = yy +} + +// xx isn't going anywhere, so taking address of yy is ok +func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" + xx = &yy +} + +func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" + *xx = yy +} + +func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" + **xx = *yy +} + +func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" + xx = yy + return *xx +} + +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" + xx = yy + return xx +} + +func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" + *xx = *yy +} + +func foo11() int { + x, y := 0, 42 + xx := &x + yy := &y + *xx = *yy + return x +} + +var xxx **int + +func foo12(yyy **int) { // ERROR "leaking param: yyy$" + xxx = yyy +} + +// Must treat yyy as leaking because *yyy leaks, and the escape analysis +// summaries in exported metadata do not distinguish these two cases. +func foo13(yyy **int) { // ERROR "leaking param content: yyy$" + *xxx = *yyy +} + +func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" + **xxx = **yyy +} + +func foo15(yy *int) { // ERROR "moved to heap: yy$" + xxx = &yy +} + +func foo16(yy *int) { // ERROR "leaking param: yy$" + *xxx = yy +} + +func foo17(yy *int) { // ERROR "foo17 yy does not escape$" + **xxx = *yy +} + +func foo18(y int) { // ERROR "moved to heap: y$" + *xxx = &y +} + +func foo19(y int) { + **xxx = y +} + +type Bar struct { + i int + ii *int +} + +func NewBar() *Bar { + return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" + return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" + return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" +} + +func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" + return *(b.ii) +} + +func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return &b.i +} + +func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii +} + +func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.ii +} + +func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" + v := 0 + b.ii = &v + return b.i +} + +func goLeak(b *Bar) { // ERROR "leaking param: b$" + go b.NoLeak() +} + +type Bar2 struct { + i [12]int + ii []int +} + +func NewBar2() *Bar2 { + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" +} + +func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" + return b.i[0] +} + +func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.i[:] +} + +func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii[0:1] +} + +func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" + return b.i +} + +func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" + b.ii = b.i[0:4] +} + +func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" + var buf []int + buf = b.i[0:] + b.ii = buf +} + +func foo21() func() int { + x := 42 + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo21a() func() int { + x := 42 // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo22() int { + x := 42 + return func() int { // ERROR "foo22 func literal does not escape$" + return x + }() +} + +func foo23(x int) func() int { + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo23a(x int) func() int { + f := func() int { // ERROR "func literal escapes to heap$" + return x + } + return f +} + +func foo23b(x int) *(func() int) { + f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" + return &f +} + +func foo23c(x int) func() int { // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo24(x int) int { + return func() int { // ERROR "foo24 func literal does not escape$" + return x + }() +} + +var x *int + +func fooleak(xx *int) int { // ERROR "leaking param: xx$" + x = xx + return *x +} + +func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" + return *x + *xx +} + +func foo31(x int) int { // ERROR "moved to heap: x$" + return fooleak(&x) +} + +func foo32(x int) int { + return foonoleak(&x) +} + +type Foo struct { + xx *int + x int +} + +var F Foo +var pf *Foo + +func (f *Foo) fooleak() { // ERROR "leaking param: f$" + pf = f +} + +func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" + F.x = f.x +} + +func (f *Foo) Leak() { // ERROR "leaking param: f$" + f.fooleak() +} + +func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" + f.foonoleak() +} + +func foo41(x int) { // ERROR "moved to heap: x$" + F.xx = &x +} + +func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo44(yy *int) { // ERROR "leaking param: yy$" + F.xx = yy +} + +func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" + F.x = f.x +} + +// See foo13 above for explanation of why f leaks. +func (f *Foo) foo46() { // ERROR "leaking param content: f$" + F.xx = f.xx +} + +func (f *Foo) foo47() { // ERROR "leaking param: f$" + f.xx = &f.x +} + +var ptrSlice []*int + +func foo50(i *int) { // ERROR "leaking param: i$" + ptrSlice[0] = i +} + +var ptrMap map[*int]*int + +func foo51(i *int) { // ERROR "leaking param: i$" + ptrMap[i] = i +} + +func indaddr1(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *&x +} + +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *(**int)(unsafe.Pointer(&x)) +} + +// From package math: + +func Float32bits(f float32) uint32 { + return *(*uint32)(unsafe.Pointer(&f)) +} + +func Float32frombits(b uint32) float32 { + return *(*float32)(unsafe.Pointer(&b)) +} + +func Float64bits(f float64) uint64 { + return *(*uint64)(unsafe.Pointer(&f)) +} + +func Float64frombits(b uint64) float64 { + return *(*float64)(unsafe.Pointer(&b)) +} + +// contrast with +func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" + return (*uint64)(unsafe.Pointer(&f)) +} + +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" + return (*uint64)(unsafe.Pointer(f)) +} + +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch val := i.(type) { + case *int: + return val + case *int8: + v := int(*val) // ERROR "moved to heap: v$" + return &v + } + return nil +} + +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch j := i; *j + 110 { + case 12: + return j + case 42: + return nil + } + return nil + +} + +// assigning to an array element is like assigning to the array +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + var a [12]*int + a[0] = i + return a[1] +} + +func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" + var a [12]*int + a[0] = i + return nil +} + +// assigning to a struct field is like assigning to the struct +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + type S struct { + a, b *int + } + var s S + s.a = i + return s.b +} + +func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" + type S struct { + a, b *int + } + var s S + s.a = i + return nil +} + +// assigning to a struct field is like assigning to the struct but +// here this subtlety is lost, since s.a counts as an assignment to a +// track-losing dereference. +func foo62(i *int) *int { // ERROR "leaking param: i$" + type S struct { + a, b *int + } + s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s.a = i + return nil // s.b +} + +type M interface { + M() +} + +func foo63(m M) { // ERROR "foo63 m does not escape$" +} + +func foo64(m M) { // ERROR "leaking param: m$" + m.M() +} + +func foo64b(m M) { // ERROR "leaking param: m$" + defer m.M() +} + +type MV int + +func (MV) M() {} + +func foo65() { + var mv MV + foo63(&mv) // ERROR "foo65 &mv does not escape$" +} + +func foo66() { + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) // ERROR "&mv escapes to heap$" +} + +func foo67() { + var mv MV + foo63(mv) // ERROR "foo67 mv does not escape$" +} + +func foo68() { + var mv MV + // escapes but it's an int so irrelevant + foo64(mv) // ERROR "mv escapes to heap$" +} + +func foo69(m M) { // ERROR "leaking param: m$" + foo64(m) +} + +func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" + m = mv1 // ERROR "mv1 escapes to heap$" + foo64(m) +} + +func foo71(x *int) []*int { // ERROR "leaking param: x$" + var y []*int + y = append(y, x) + return y +} + +func foo71a(x int) []*int { // ERROR "moved to heap: x$" + var y []*int + y = append(y, &x) + return y +} + +func foo72() { + var x int + var y [1]*int + y[0] = &x +} + +func foo72aa() [10]*int { + var x int // ERROR "moved to heap: x$" + var y [10]*int + y[0] = &x + return y +} + +func foo72a() { + var y [10]*int + for i := 0; i < 10; i++ { + // escapes its scope + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return +} + +func foo72b() [10]*int { + var y [10]*int + for i := 0; i < 10; i++ { + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return y +} + +// issue 2145 +func foo73() { + s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + println(vv) + }() + } +} + +func foo731() { + s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + vv = 42 + println(vv) + }() + } +} + +func foo74() { + s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + println(vv) + } + defer fn() + } +} + +func foo74a() { + s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + vv += 1 + println(vv) + } + defer fn() + } +} + +// issue 3975 +func foo74b() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" + for i, v := range s { + vv := v + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(vv) + } + } +} + +func foo74c() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" + for i, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(&vv) + } + } +} + +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" + return y +} + +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" + return &x[0] +} + +func foo75(z *int) { // ERROR "foo75 z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +} + +func foo75a(z *int) { // ERROR "foo75a z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +} + +func foo75esc(z *int) { // ERROR "leaking param: z$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" +} + +func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" + var ppi **interface{} // assignments to pointer dereferences lose track + *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 "foo75aesc1 z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +} + +func foo76(z *int) { // ERROR "z does not escape" + myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" +} + +func foo76a(z *int) { // ERROR "z does not escape" + myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" +} + +func foo76b() { + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" +} + +func foo76c() { + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" +} + +func foo76d() { + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" +} + +func foo76e() { + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" +} + +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$" "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$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" + myprint(nil, z...) // z does not escape +} + +func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" + myprint1(nil, z...) +} + +func foo77b(z []interface{}) { // ERROR "leaking param: z$" + var ppi **interface{} + *ppi = myprint1(nil, z...) +} + +func foo77c(z []interface{}) { // ERROR "leaking param: z$" + sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" +} + +func dotdotdot() { + i := 0 + myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + + j := 0 + myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" +} + +func foo78(z int) *int { // ERROR "moved to heap: z$" + return &z +} + +func foo78a(z int) *int { // ERROR "moved to heap: z$" + y := &z + x := &y + return *x // really return y +} + +func foo79() *int { + return new(int) // ERROR "new\(int\) escapes to heap$" +} + +func foo80() *int { + var z *int + for { + // Really just escapes its scope but we don't distinguish + z = new(int) // ERROR "new\(int\) escapes to heap$" + } + _ = z + return nil +} + +func foo81() *int { + for { + z := new(int) // ERROR "foo81 new\(int\) does not escape$" + _ = z + } + return nil +} + +func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" + +func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" + +func foo82() { + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + go noop(tee(&z)) + go noop(&x, &y) + for { + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + defer noop(tee(&u)) + defer noop(&v, &w) + } +} + +type Fooer interface { + Foo() +} + +type LimitedFooer struct { + Fooer + N int64 +} + +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" +} + +func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" + return [2]*int{x, nil} +} + +// does not leak c +func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" + for v := range c { + return v + } + return nil +} + +// does not leak m +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" + for k, v := range m { + if b { + return k + } + return v + } + return nil +} + +// does leak x +func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" + m[x] = x +} + +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + return m[0] +} + +// does leak m +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[0] +} + +// does not leak m +func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" + return m[0] +} + +// does leak m +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[:] +} + +// does not leak m +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + for _, v := range m { + return v + } + return nil +} + +// does leak m +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + for _, v := range m { + return v + } + return nil +} + +// does not leak m +func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" + for i := range m { // ERROR "moved to heap: i$" + return &i + } + return nil +} + +// does leak x +func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" + m[0] = x +} + +// does not leak x +func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" + m[0] = x +} + +var y []*int + +// does not leak x but does leak content +func foo104(x []*int) { // ERROR "leaking param content: x" + copy(y, x) +} + +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" + _ = append(y, x...) +} + +// does leak x +func foo106(x *int) { // ERROR "leaking param: x$" + _ = append(y, x) +} + +func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo109(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + for k, _ := range m { + return k + } + return nil +} + +func foo110(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" + return m[nil] +} + +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" + m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + return m[0] +} + +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := [1]*int{x} + return m[0] +} + +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := Bar{ii: x} + return m.ii +} + +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" + return m.ii +} + +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) +} + +func foo116(b bool) *int { + if b { + x := 1 // ERROR "moved to heap: x$" + return &x + } else { + y := 1 // ERROR "moved to heap: y$" + return &y + } + return nil +} + +func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) // ERROR "&x escapes to heap$" +} + +func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) +} + +func external(*int) + +func foo119(x *int) { // ERROR "leaking param: x$" + external(x) +} + +func foo120() { + // formerly exponential time analysis +L1: +L2: +L3: +L4: +L5: +L6: +L7: +L8: +L9: +L10: +L11: +L12: +L13: +L14: +L15: +L16: +L17: +L18: +L19: +L20: +L21: +L22: +L23: +L24: +L25: +L26: +L27: +L28: +L29: +L30: +L31: +L32: +L33: +L34: +L35: +L36: +L37: +L38: +L39: +L40: +L41: +L42: +L43: +L44: +L45: +L46: +L47: +L48: +L49: +L50: +L51: +L52: +L53: +L54: +L55: +L56: +L57: +L58: +L59: +L60: +L61: +L62: +L63: +L64: +L65: +L66: +L67: +L68: +L69: +L70: +L71: +L72: +L73: +L74: +L75: +L76: +L77: +L78: +L79: +L80: +L81: +L82: +L83: +L84: +L85: +L86: +L87: +L88: +L89: +L90: +L91: +L92: +L93: +L94: +L95: +L96: +L97: +L98: +L99: +L100: + // use the labels to silence compiler errors + goto L1 + goto L2 + goto L3 + goto L4 + goto L5 + goto L6 + goto L7 + goto L8 + goto L9 + goto L10 + goto L11 + goto L12 + goto L13 + goto L14 + goto L15 + goto L16 + goto L17 + goto L18 + goto L19 + goto L20 + goto L21 + goto L22 + goto L23 + goto L24 + goto L25 + goto L26 + goto L27 + goto L28 + goto L29 + goto L30 + goto L31 + goto L32 + goto L33 + goto L34 + goto L35 + goto L36 + goto L37 + goto L38 + goto L39 + goto L40 + goto L41 + goto L42 + goto L43 + goto L44 + goto L45 + goto L46 + goto L47 + goto L48 + goto L49 + goto L50 + goto L51 + goto L52 + goto L53 + goto L54 + goto L55 + goto L56 + goto L57 + goto L58 + goto L59 + goto L60 + goto L61 + goto L62 + goto L63 + goto L64 + goto L65 + goto L66 + goto L67 + goto L68 + goto L69 + goto L70 + goto L71 + goto L72 + goto L73 + goto L74 + goto L75 + goto L76 + goto L77 + goto L78 + goto L79 + goto L80 + goto L81 + goto L82 + goto L83 + goto L84 + goto L85 + goto L86 + goto L87 + goto L88 + goto L89 + goto L90 + goto L91 + goto L92 + goto L93 + goto L94 + goto L95 + goto L96 + goto L97 + goto L98 + goto L99 + goto L100 +} + +func foo121() { + for i := 0; i < 10; i++ { + 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$" "i escapes to heap$" + go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// a harmless forward jump +func foo122() { + var i *int + + goto L1 +L1: + i = new(int) // ERROR "foo122 new\(int\) does not escape$" + _ = i +} + +// a backward jump, increases loopdepth +func foo123() { + var i *int + +L1: + i = new(int) // ERROR "new\(int\) escapes to heap$" + + goto L1 + _ = i +} + +func foo124(x **int) { // ERROR "foo124 x does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo124 func literal does not escape$" + *x = p + }() +} + +func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo125 func literal does not escape$" + ch <- p + }() +} + +func foo126() { + var px *int // loopdepth 0 + for { + // loopdepth 1 + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo126 func literal does not escape$" + px = &i + }() + } + _ = px +} + +var px *int + +func foo127() { + var i int // ERROR "moved to heap: i$" + p := &i + q := p + px = q +} + +func foo128() { + var i int + p := &i + q := p + _ = q +} + +func foo129() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo129 func literal does not escape$" + q := p + func() { // ERROR "foo129.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo130() { + for { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo130 func literal does not escape$" + px = &i + }() + } +} + +func foo131() { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo131 func literal does not escape$" + px = &i + }() +} + +func foo132() { + var i int // ERROR "moved to heap: i$" + go func() { // ERROR "func literal escapes to heap$" + px = &i + }() +} + +func foo133() { + var i int // ERROR "moved to heap: i$" + defer func() { // ERROR "foo133 func literal does not escape$" + px = &i + }() +} + +func foo134() { + var i int + p := &i + func() { // ERROR "foo134 func literal does not escape$" + q := p + func() { // ERROR "foo134.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo135() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo135.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo136() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo136.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo137() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo137 func literal does not escape$" + q := p + go func() { // ERROR "func literal escapes to heap$" + r := q + _ = r + }() + }() +} + +func foo138() *byte { + type T struct { + x [1]byte + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x[0] +} + +func foo139() *byte { + type T struct { + x struct { + y byte + } + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x.y +} + +// issue 4751 +func foo140() interface{} { + type T struct { + X string + } + type U struct { + X string + T *T + } + t := &T{} // ERROR "&T literal escapes to heap$" + return U{ // ERROR "U literal escapes to heap$" + X: t.X, + T: t, + } +} + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape$" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) + + var buf2 [10]byte // ERROR "moved to heap: buf2$" + F2(buf2[:]) + + var buf3 [10]byte + F3(buf3[:]) + + var buf4 [10]byte // ERROR "moved to heap: buf4$" + F4(buf4[:]) +} + +type Tm struct { + x int +} + +func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +} + +func foo141() { + var f func() + + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + f = t.M // ERROR "foo141 t.M does not escape$" + _ = f +} + +var gf func() + +func foo142() { + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + gf = t.M // ERROR "t.M escapes to heap$" +} + +// issue 3888. +func foo143() { + for i := 0; i < 1000; i++ { + func() { // ERROR "foo143 func literal does not escape$" + for i := 0; i < 1; i++ { + var t Tm + t.M() + } + }() + } +} + +// issue 5773 +// Check that annotations take effect regardless of whether they +// are before or after the use in the source code. + +//go:noescape + +func foo144a(*int) + +func foo144() { + var x int + foo144a(&x) + var y int + foo144b(&y) +} + +//go:noescape + +func foo144b(*int) + +// issue 7313: for loop init should not be treated as "in loop" + +type List struct { + Next *List +} + +func foo145(l List) { // ERROR "foo145 l does not escape$" + var p *List + for p = &l; p.Next != nil; p = p.Next { + } +} + +func foo146(l List) { // ERROR "foo146 l does not escape$" + var p *List + p = &l + for ; p.Next != nil; p = p.Next { + } +} + +func foo147(l List) { // ERROR "foo147 l does not escape$" + var p *List + p = &l + for p.Next != nil { + p = p.Next + } +} + +func foo148(l List) { // ERROR "foo148 l does not escape$" + for p := &l; p.Next != nil; p = p.Next { + } +} + +// related: address of variable should have depth of variable, not of loop + +func foo149(l List) { // ERROR "foo149 l does not escape$" + var p *List + for { + for p = &l; p.Next != nil; p = p.Next { + } + } +} + +// issue 7934: missed ... if element type had no pointers + +var save150 []byte + +func foo150(x ...byte) { // ERROR "leaking param: x$" + save150 = x +} + +func bar150() { + foo150(1, 2, 3) // ERROR "... argument escapes to heap$" +} + +// issue 7931: bad handling of slice of array + +var save151 *int + +func foo151(x *int) { // ERROR "leaking param: x$" + save151 = x +} + +func bar151() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8][0]) +} + +func bar151b() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8][0]) +} + +func bar151c() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8:8][0]) +} + +func bar151d() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8:8][0]) +} + +// issue 8120 + +type U struct { + s *string +} + +func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" + return u.s +} + +type V struct { + s *string +} + +// BAD -- level of leak ought to be 0 +func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" + return &V{u.String()} // ERROR "&V literal escapes to heap$" +} + +func foo152() { + a := "a" // ERROR "moved to heap: a$" + u := U{&a} + v := NewV(u) + println(v) +} + +// issue 8176 - &x in type switch body not marked as escaping + +func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" + switch x := v.(type) { + case int: // ERROR "moved to heap: x$" + return &x + } + panic(0) +} + +// issue 8185 - &result escaping into result + +func f() (x int, y *int) { // ERROR "moved to heap: x$" + y = &x + return +} + +func g() (x interface{}) { // ERROR "moved to heap: x$" + x = &x // ERROR "&x escapes to heap$" + return +} + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" + 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$" + sink = x // ERROR "x escapes to heap$" +} + +// self-assignments + +type Buffer struct { + arr [64]byte + arrPtr *[64]byte + buf1 []byte + buf2 []byte + str1 string + str2 string +} + +func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" + b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" + b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" + b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" + b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" +} + +func (b *Buffer) bar() { // ERROR "leaking param: b$" + b.buf1 = b.arr[1:2] +} + +func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" + b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" + b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" +} + +func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" + b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" + b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" +} + +func (b *Buffer) bat() { // ERROR "leaking param content: b$" + o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" + o.buf1 = b.buf1[1:2] + sink = o // ERROR "o escapes to heap$" +} + +func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" + *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" + *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" +} + +type StructWithString struct { + p *int + s string +} + +// This is escape analysis false negative. +// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows +// to just x, and thus &i looks escaping. +func fieldFlowTracking() { + var x StructWithString + i := 0 // ERROR "moved to heap: i$" + x.p = &i + sink = x.s // ERROR "x.s escapes to heap$" +} + +// String operations. + +func slicebytetostring0() { + b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + _ = s +} + +func slicebytetostring1() { + b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + s1 := s[0:1] + _ = s1 +} + +func slicebytetostring2() { + b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] // ERROR "moved to heap: s1$" + sink = &s1 // ERROR "&s1 escapes to heap$" +} + +func slicebytetostring3() { + b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] + sink = s1 // ERROR "s1 escapes to heap$" +} + +func addstr0() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + _ = s +} + +func addstr1() { + s0 := "a" + s1 := "b" + s := "c" + s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + _ = s +} + +func addstr2() { + b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + s0 := "a" + s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + _ = s +} + +func addstr3() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" + s2 := s[0:1] + sink = s2 // ERROR "s2 escapes to heap$" +} + +func intstring0() bool { + // string does not escape + x := '0' + s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + return s == "0" +} + +func intstring1() string { + // string does not escape, but the buffer does + x := '0' + s := string(x) // ERROR "string\(x\) escapes to heap$" + return s +} + +func intstring2() { + // string escapes to heap + x := '0' + s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" + sink = &s // ERROR "&s escapes to heap$" +} + +func stringtoslicebyte0() { + s := "foo" + x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + _ = x +} + +func stringtoslicebyte1() []byte { + s := "foo" + return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicebyte2() { + s := "foo" + sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicerune0() { + s := "foo" + x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + _ = x +} + +func stringtoslicerune1() []rune { + s := "foo" + return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func stringtoslicerune2() { + s := "foo" + sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func slicerunetostring0() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" + s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + _ = s +} + +func slicerunetostring1() string { + r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + return string(r) // ERROR "string\(r\) escapes to heap$" +} + +func slicerunetostring2() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + sink = string(r) // ERROR "string\(r\) escapes to heap$" +} + +func makemap0() { + m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m[0] = 0 + m[1]++ + delete(m, 1) + sink = m[0] // ERROR "m\[0\] escapes to heap$" +} + +func makemap1() map[int]int { + return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" +} + +func makemap2() { + m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" + sink = m // ERROR "m escapes to heap$" +} + +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" + return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +} + +func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" + return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +} + +func issue10353() { + x := new(int) // ERROR "new\(int\) escapes to heap$" + issue10353a(x)() +} + +func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" + return func() { // ERROR "func literal escapes to heap$" + println(*x) + } +} + +func issue10353b() { + var f func() + for { + x := new(int) // ERROR "new\(int\) escapes to heap$" + f = func() { // ERROR "func literal escapes to heap$" + println(*x) + } + } + _ = f +} + +func issue11387(x int) func() int { + f := func() int { return x } // ERROR "func literal escapes to heap" + slice1 := []func() int{f} // ERROR "\[\].* does not escape" + slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" + copy(slice2, slice1) + return slice2[0] +} + +func issue12397(x, y int) { // ERROR "moved to heap: y$" + // x does not escape below, because all relevant code is dead. + if false { + gxx = &x + } else { + gxx = &y + } + + if true { + gxx = &y + } else { + gxx = &x + } +} diff --git a/test/oldescape2n.go b/test/oldescape2n.go new file mode 100644 index 00000000..fb2a9566 --- /dev/null +++ b/test/oldescape2n.go @@ -0,0 +1,1847 @@ +// errorcheck -0 -N -m -l -newescape=false + +// Copyright 2010 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, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. +// Registerization is disabled too (-N), which should +// have no effect on escape analysis. + +package foo + +import ( + "fmt" + "unsafe" +) + +var gxx *int + +func foo1(x int) { // ERROR "moved to heap: x$" + gxx = &x +} + +func foo2(yy *int) { // ERROR "leaking param: yy$" + gxx = yy +} + +func foo3(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +type T *T + +func foo3b(t T) { // ERROR "leaking param: t$" + *t = t +} + +// xx isn't going anywhere, so use of yy is ok +func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" + xx = yy +} + +// xx isn't going anywhere, so taking address of yy is ok +func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" + xx = &yy +} + +func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" + *xx = yy +} + +func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" + **xx = *yy +} + +func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" + xx = yy + return *xx +} + +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" + xx = yy + return xx +} + +func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" + *xx = *yy +} + +func foo11() int { + x, y := 0, 42 + xx := &x + yy := &y + *xx = *yy + return x +} + +var xxx **int + +func foo12(yyy **int) { // ERROR "leaking param: yyy$" + xxx = yyy +} + +// Must treat yyy as leaking because *yyy leaks, and the escape analysis +// summaries in exported metadata do not distinguish these two cases. +func foo13(yyy **int) { // ERROR "leaking param content: yyy$" + *xxx = *yyy +} + +func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" + **xxx = **yyy +} + +func foo15(yy *int) { // ERROR "moved to heap: yy$" + xxx = &yy +} + +func foo16(yy *int) { // ERROR "leaking param: yy$" + *xxx = yy +} + +func foo17(yy *int) { // ERROR "foo17 yy does not escape$" + **xxx = *yy +} + +func foo18(y int) { // ERROR "moved to heap: y$" + *xxx = &y +} + +func foo19(y int) { + **xxx = y +} + +type Bar struct { + i int + ii *int +} + +func NewBar() *Bar { + return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" + return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" +} + +func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" + return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" +} + +func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" + return *(b.ii) +} + +func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return &b.i +} + +func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii +} + +func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.ii +} + +func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" + v := 0 // ERROR "moved to heap: v$" + b.ii = &v + return b.ii +} + +func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" + v := 0 + b.ii = &v + return b.i +} + +func goLeak(b *Bar) { // ERROR "leaking param: b$" + go b.NoLeak() +} + +type Bar2 struct { + i [12]int + ii []int +} + +func NewBar2() *Bar2 { + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" +} + +func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" + return b.i[0] +} + +func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" + return b.i[:] +} + +func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" + return b.ii[0:1] +} + +func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" + return b.i +} + +func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" + b.ii = b.i[0:4] +} + +func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" + var buf []int + buf = b.i[0:] + b.ii = buf +} + +func foo21() func() int { + x := 42 + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo21a() func() int { + x := 42 // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo22() int { + x := 42 + return func() int { // ERROR "foo22 func literal does not escape$" + return x + }() +} + +func foo23(x int) func() int { + return func() int { // ERROR "func literal escapes to heap$" + return x + } +} + +func foo23a(x int) func() int { + f := func() int { // ERROR "func literal escapes to heap$" + return x + } + return f +} + +func foo23b(x int) *(func() int) { + f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" + return &f +} + +func foo23c(x int) func() int { // ERROR "moved to heap: x$" + return func() int { // ERROR "func literal escapes to heap$" + x++ + return x + } +} + +func foo24(x int) int { + return func() int { // ERROR "foo24 func literal does not escape$" + return x + }() +} + +var x *int + +func fooleak(xx *int) int { // ERROR "leaking param: xx$" + x = xx + return *x +} + +func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" + return *x + *xx +} + +func foo31(x int) int { // ERROR "moved to heap: x$" + return fooleak(&x) +} + +func foo32(x int) int { + return foonoleak(&x) +} + +type Foo struct { + xx *int + x int +} + +var F Foo +var pf *Foo + +func (f *Foo) fooleak() { // ERROR "leaking param: f$" + pf = f +} + +func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" + F.x = f.x +} + +func (f *Foo) Leak() { // ERROR "leaking param: f$" + f.fooleak() +} + +func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" + f.foonoleak() +} + +func foo41(x int) { // ERROR "moved to heap: x$" + F.xx = &x +} + +func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" + f.xx = &x +} + +func foo44(yy *int) { // ERROR "leaking param: yy$" + F.xx = yy +} + +func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" + F.x = f.x +} + +// See foo13 above for explanation of why f leaks. +func (f *Foo) foo46() { // ERROR "leaking param content: f$" + F.xx = f.xx +} + +func (f *Foo) foo47() { // ERROR "leaking param: f$" + f.xx = &f.x +} + +var ptrSlice []*int + +func foo50(i *int) { // ERROR "leaking param: i$" + ptrSlice[0] = i +} + +var ptrMap map[*int]*int + +func foo51(i *int) { // ERROR "leaking param: i$" + ptrMap[i] = i +} + +func indaddr1(x int) *int { // ERROR "moved to heap: x$" + return &x +} + +func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *&x +} + +func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return *(**int)(unsafe.Pointer(&x)) +} + +// From package math: + +func Float32bits(f float32) uint32 { + return *(*uint32)(unsafe.Pointer(&f)) +} + +func Float32frombits(b uint32) float32 { + return *(*float32)(unsafe.Pointer(&b)) +} + +func Float64bits(f float64) uint64 { + return *(*uint64)(unsafe.Pointer(&f)) +} + +func Float64frombits(b uint64) float64 { + return *(*float64)(unsafe.Pointer(&b)) +} + +// contrast with +func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" + return (*uint64)(unsafe.Pointer(&f)) +} + +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" + return (*uint64)(unsafe.Pointer(f)) +} + +func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch val := i.(type) { + case *int: + return val + case *int8: + v := int(*val) // ERROR "moved to heap: v$" + return &v + } + return nil +} + +func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + switch j := i; *j + 110 { + case 12: + return j + case 42: + return nil + } + return nil + +} + +// assigning to an array element is like assigning to the array +func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + var a [12]*int + a[0] = i + return a[1] +} + +func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" + var a [12]*int + a[0] = i + return nil +} + +// assigning to a struct field is like assigning to the struct +func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" + type S struct { + a, b *int + } + var s S + s.a = i + return s.b +} + +func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" + type S struct { + a, b *int + } + var s S + s.a = i + return nil +} + +// assigning to a struct field is like assigning to the struct but +// here this subtlety is lost, since s.a counts as an assignment to a +// track-losing dereference. +func foo62(i *int) *int { // ERROR "leaking param: i$" + type S struct { + a, b *int + } + s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s.a = i + return nil // s.b +} + +type M interface { + M() +} + +func foo63(m M) { // ERROR "foo63 m does not escape$" +} + +func foo64(m M) { // ERROR "leaking param: m$" + m.M() +} + +func foo64b(m M) { // ERROR "leaking param: m$" + defer m.M() +} + +type MV int + +func (MV) M() {} + +func foo65() { + var mv MV + foo63(&mv) // ERROR "foo65 &mv does not escape$" +} + +func foo66() { + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) // ERROR "&mv escapes to heap$" +} + +func foo67() { + var mv MV + foo63(mv) // ERROR "foo67 mv does not escape$" +} + +func foo68() { + var mv MV + // escapes but it's an int so irrelevant + foo64(mv) // ERROR "mv escapes to heap$" +} + +func foo69(m M) { // ERROR "leaking param: m$" + foo64(m) +} + +func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" + m = mv1 // ERROR "mv1 escapes to heap$" + foo64(m) +} + +func foo71(x *int) []*int { // ERROR "leaking param: x$" + var y []*int + y = append(y, x) + return y +} + +func foo71a(x int) []*int { // ERROR "moved to heap: x$" + var y []*int + y = append(y, &x) + return y +} + +func foo72() { + var x int + var y [1]*int + y[0] = &x +} + +func foo72aa() [10]*int { + var x int // ERROR "moved to heap: x$" + var y [10]*int + y[0] = &x + return y +} + +func foo72a() { + var y [10]*int + for i := 0; i < 10; i++ { + // escapes its scope + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return +} + +func foo72b() [10]*int { + var y [10]*int + for i := 0; i < 10; i++ { + x := i // ERROR "moved to heap: x$" + y[i] = &x + } + return y +} + +// issue 2145 +func foo73() { + s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + println(vv) + }() + } +} + +func foo731() { + s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap$" + vv = 42 + println(vv) + }() + } +} + +func foo74() { + s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" + for _, v := range s { + vv := v + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + println(vv) + } + defer fn() + } +} + +func foo74a() { + s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" + for _, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap$" + vv += 1 + println(vv) + } + defer fn() + } +} + +// issue 3975 +func foo74b() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" + for i, v := range s { + vv := v + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(vv) + } + } +} + +func foo74c() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" + for i, v := range s { + vv := v // ERROR "moved to heap: vv$" + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap$" + println(&vv) + } + } +} + +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" + return y +} + +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" + return &x[0] +} + +func foo75(z *int) { // ERROR "foo75 z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +} + +func foo75a(z *int) { // ERROR "foo75a z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +} + +func foo75esc(z *int) { // ERROR "leaking param: z$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" +} + +func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" + var ppi **interface{} // assignments to pointer dereferences lose track + *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 "foo75aesc1 z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +} + +func foo76(z *int) { // ERROR "z does not escape" + myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" +} + +func foo76a(z *int) { // ERROR "z does not escape" + myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" +} + +func foo76b() { + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" +} + +func foo76c() { + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" +} + +func foo76d() { + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" +} + +func foo76e() { + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" +} + +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$" "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$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" + } +} + +func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" + myprint(nil, z...) // z does not escape +} + +func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" + myprint1(nil, z...) +} + +func foo77b(z []interface{}) { // ERROR "leaking param: z$" + var ppi **interface{} + *ppi = myprint1(nil, z...) +} + +func foo77c(z []interface{}) { // ERROR "leaking param: z$" + sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" +} + +func dotdotdot() { + i := 0 + myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + + j := 0 + myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" +} + +func foo78(z int) *int { // ERROR "moved to heap: z$" + return &z +} + +func foo78a(z int) *int { // ERROR "moved to heap: z$" + y := &z + x := &y + return *x // really return y +} + +func foo79() *int { + return new(int) // ERROR "new\(int\) escapes to heap$" +} + +func foo80() *int { + var z *int + for { + // Really just escapes its scope but we don't distinguish + z = new(int) // ERROR "new\(int\) escapes to heap$" + } + _ = z + return nil +} + +func foo81() *int { + for { + z := new(int) // ERROR "foo81 new\(int\) does not escape$" + _ = z + } + return nil +} + +func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" + +func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" + +func foo82() { + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + go noop(tee(&z)) + go noop(&x, &y) + for { + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + defer noop(tee(&u)) + defer noop(&v, &w) + } +} + +type Fooer interface { + Foo() +} + +type LimitedFooer struct { + Fooer + N int64 +} + +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" +} + +func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" + return [2]*int{x, nil} +} + +// does not leak c +func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" + for v := range c { + return v + } + return nil +} + +// does not leak m +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" + for k, v := range m { + if b { + return k + } + return v + } + return nil +} + +// does leak x +func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" + m[x] = x +} + +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + return m[0] +} + +// does leak m +func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[0] +} + +// does not leak m +func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" + return m[0] +} + +// does leak m +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" + return m[:] +} + +// does not leak m +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" + for _, v := range m { + return v + } + return nil +} + +// does leak m +func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" + for _, v := range m { + return v + } + return nil +} + +// does not leak m +func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" + for i := range m { // ERROR "moved to heap: i$" + return &i + } + return nil +} + +// does leak x +func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" + m[0] = x +} + +// does not leak x +func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" + m[0] = x +} + +var y []*int + +// does not leak x but does leak content +func foo104(x []*int) { // ERROR "leaking param content: x" + copy(y, x) +} + +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" + _ = append(y, x...) +} + +// does leak x +func foo106(x *int) { // ERROR "leaking param: x$" + _ = append(y, x) +} + +func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" +} + +func foo109(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + for k, _ := range m { + return k + } + return nil +} + +func foo110(x *int) *int { // ERROR "leaking param: x$" + m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" + return m[nil] +} + +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" + m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + return m[0] +} + +func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := [1]*int{x} + return m[0] +} + +func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := Bar{ii: x} + return m.ii +} + +func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" + return m.ii +} + +func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" + return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) +} + +func foo116(b bool) *int { + if b { + x := 1 // ERROR "moved to heap: x$" + return &x + } else { + y := 1 // ERROR "moved to heap: y$" + return &y + } + return nil +} + +func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) // ERROR "&x escapes to heap$" +} + +func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) +} + +func external(*int) + +func foo119(x *int) { // ERROR "leaking param: x$" + external(x) +} + +func foo120() { + // formerly exponential time analysis +L1: +L2: +L3: +L4: +L5: +L6: +L7: +L8: +L9: +L10: +L11: +L12: +L13: +L14: +L15: +L16: +L17: +L18: +L19: +L20: +L21: +L22: +L23: +L24: +L25: +L26: +L27: +L28: +L29: +L30: +L31: +L32: +L33: +L34: +L35: +L36: +L37: +L38: +L39: +L40: +L41: +L42: +L43: +L44: +L45: +L46: +L47: +L48: +L49: +L50: +L51: +L52: +L53: +L54: +L55: +L56: +L57: +L58: +L59: +L60: +L61: +L62: +L63: +L64: +L65: +L66: +L67: +L68: +L69: +L70: +L71: +L72: +L73: +L74: +L75: +L76: +L77: +L78: +L79: +L80: +L81: +L82: +L83: +L84: +L85: +L86: +L87: +L88: +L89: +L90: +L91: +L92: +L93: +L94: +L95: +L96: +L97: +L98: +L99: +L100: + // use the labels to silence compiler errors + goto L1 + goto L2 + goto L3 + goto L4 + goto L5 + goto L6 + goto L7 + goto L8 + goto L9 + goto L10 + goto L11 + goto L12 + goto L13 + goto L14 + goto L15 + goto L16 + goto L17 + goto L18 + goto L19 + goto L20 + goto L21 + goto L22 + goto L23 + goto L24 + goto L25 + goto L26 + goto L27 + goto L28 + goto L29 + goto L30 + goto L31 + goto L32 + goto L33 + goto L34 + goto L35 + goto L36 + goto L37 + goto L38 + goto L39 + goto L40 + goto L41 + goto L42 + goto L43 + goto L44 + goto L45 + goto L46 + goto L47 + goto L48 + goto L49 + goto L50 + goto L51 + goto L52 + goto L53 + goto L54 + goto L55 + goto L56 + goto L57 + goto L58 + goto L59 + goto L60 + goto L61 + goto L62 + goto L63 + goto L64 + goto L65 + goto L66 + goto L67 + goto L68 + goto L69 + goto L70 + goto L71 + goto L72 + goto L73 + goto L74 + goto L75 + goto L76 + goto L77 + goto L78 + goto L79 + goto L80 + goto L81 + goto L82 + goto L83 + goto L84 + goto L85 + goto L86 + goto L87 + goto L88 + goto L89 + goto L90 + goto L91 + goto L92 + goto L93 + goto L94 + goto L95 + goto L96 + goto L97 + goto L98 + goto L99 + goto L100 +} + +func foo121() { + for i := 0; i < 10; i++ { + 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$" "i escapes to heap$" + go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" + } +} + +// a harmless forward jump +func foo122() { + var i *int + + goto L1 +L1: + i = new(int) // ERROR "foo122 new\(int\) does not escape$" + _ = i +} + +// a backward jump, increases loopdepth +func foo123() { + var i *int + +L1: + i = new(int) // ERROR "new\(int\) escapes to heap$" + + goto L1 + _ = i +} + +func foo124(x **int) { // ERROR "foo124 x does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo124 func literal does not escape$" + *x = p + }() +} + +func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo125 func literal does not escape$" + ch <- p + }() +} + +func foo126() { + var px *int // loopdepth 0 + for { + // loopdepth 1 + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo126 func literal does not escape$" + px = &i + }() + } + _ = px +} + +var px *int + +func foo127() { + var i int // ERROR "moved to heap: i$" + p := &i + q := p + px = q +} + +func foo128() { + var i int + p := &i + q := p + _ = q +} + +func foo129() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo129 func literal does not escape$" + q := p + func() { // ERROR "foo129.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo130() { + for { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo130 func literal does not escape$" + px = &i + }() + } +} + +func foo131() { + var i int // ERROR "moved to heap: i$" + func() { // ERROR "foo131 func literal does not escape$" + px = &i + }() +} + +func foo132() { + var i int // ERROR "moved to heap: i$" + go func() { // ERROR "func literal escapes to heap$" + px = &i + }() +} + +func foo133() { + var i int // ERROR "moved to heap: i$" + defer func() { // ERROR "foo133 func literal does not escape$" + px = &i + }() +} + +func foo134() { + var i int + p := &i + func() { // ERROR "foo134 func literal does not escape$" + q := p + func() { // ERROR "foo134.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo135() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo135.func1 func literal does not escape$" + r := q + _ = r + }() + }() +} + +func foo136() { + var i int // ERROR "moved to heap: i$" + p := &i + go func() { // ERROR "func literal escapes to heap$" + q := p + func() { // ERROR "foo136.func1 func literal does not escape$" + r := q + px = r + }() + }() +} + +func foo137() { + var i int // ERROR "moved to heap: i$" + p := &i + func() { // ERROR "foo137 func literal does not escape$" + q := p + go func() { // ERROR "func literal escapes to heap$" + r := q + _ = r + }() + }() +} + +func foo138() *byte { + type T struct { + x [1]byte + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x[0] +} + +func foo139() *byte { + type T struct { + x struct { + y byte + } + } + t := new(T) // ERROR "new\(T\) escapes to heap$" + return &t.x.y +} + +// issue 4751 +func foo140() interface{} { + type T struct { + X string + } + type U struct { + X string + T *T + } + t := &T{} // ERROR "&T literal escapes to heap$" + return U{ // ERROR "U literal escapes to heap$" + X: t.X, + T: t, + } +} + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape$" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) + + var buf2 [10]byte // ERROR "moved to heap: buf2$" + F2(buf2[:]) + + var buf3 [10]byte + F3(buf3[:]) + + var buf4 [10]byte // ERROR "moved to heap: buf4$" + F4(buf4[:]) +} + +type Tm struct { + x int +} + +func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +} + +func foo141() { + var f func() + + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + f = t.M // ERROR "foo141 t.M does not escape$" + _ = f +} + +var gf func() + +func foo142() { + t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" + gf = t.M // ERROR "t.M escapes to heap$" +} + +// issue 3888. +func foo143() { + for i := 0; i < 1000; i++ { + func() { // ERROR "foo143 func literal does not escape$" + for i := 0; i < 1; i++ { + var t Tm + t.M() + } + }() + } +} + +// issue 5773 +// Check that annotations take effect regardless of whether they +// are before or after the use in the source code. + +//go:noescape + +func foo144a(*int) + +func foo144() { + var x int + foo144a(&x) + var y int + foo144b(&y) +} + +//go:noescape + +func foo144b(*int) + +// issue 7313: for loop init should not be treated as "in loop" + +type List struct { + Next *List +} + +func foo145(l List) { // ERROR "foo145 l does not escape$" + var p *List + for p = &l; p.Next != nil; p = p.Next { + } +} + +func foo146(l List) { // ERROR "foo146 l does not escape$" + var p *List + p = &l + for ; p.Next != nil; p = p.Next { + } +} + +func foo147(l List) { // ERROR "foo147 l does not escape$" + var p *List + p = &l + for p.Next != nil { + p = p.Next + } +} + +func foo148(l List) { // ERROR "foo148 l does not escape$" + for p := &l; p.Next != nil; p = p.Next { + } +} + +// related: address of variable should have depth of variable, not of loop + +func foo149(l List) { // ERROR "foo149 l does not escape$" + var p *List + for { + for p = &l; p.Next != nil; p = p.Next { + } + } +} + +// issue 7934: missed ... if element type had no pointers + +var save150 []byte + +func foo150(x ...byte) { // ERROR "leaking param: x$" + save150 = x +} + +func bar150() { + foo150(1, 2, 3) // ERROR "... argument escapes to heap$" +} + +// issue 7931: bad handling of slice of array + +var save151 *int + +func foo151(x *int) { // ERROR "leaking param: x$" + save151 = x +} + +func bar151() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8][0]) +} + +func bar151b() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8][0]) +} + +func bar151c() { + var a [64]int // ERROR "moved to heap: a$" + a[4] = 101 + foo151(&(&a)[4:8:8][0]) +} + +func bar151d() { + var a [10]int // ERROR "moved to heap: a$" + b := a[:] + foo151(&b[4:8:8][0]) +} + +// issue 8120 + +type U struct { + s *string +} + +func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" + return u.s +} + +type V struct { + s *string +} + +// BAD -- level of leak ought to be 0 +func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" + return &V{u.String()} // ERROR "&V literal escapes to heap$" +} + +func foo152() { + a := "a" // ERROR "moved to heap: a$" + u := U{&a} + v := NewV(u) + println(v) +} + +// issue 8176 - &x in type switch body not marked as escaping + +func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" + switch x := v.(type) { + case int: // ERROR "moved to heap: x$" + return &x + } + panic(0) +} + +// issue 8185 - &result escaping into result + +func f() (x int, y *int) { // ERROR "moved to heap: x$" + y = &x + return +} + +func g() (x interface{}) { // ERROR "moved to heap: x$" + x = &x // ERROR "&x escapes to heap$" + return +} + +var sink interface{} + +type Lit struct { + p *int +} + +func ptrlitNoescape() { + // Both literal and element do not escape. + i := 0 + x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + _ = x +} + +func ptrlitNoEscape2() { + // Literal does not escape, but element does. + i := 0 // ERROR "moved to heap: i$" + x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" + 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$" + sink = x // ERROR "x escapes to heap$" +} + +// self-assignments + +type Buffer struct { + arr [64]byte + arrPtr *[64]byte + buf1 []byte + buf2 []byte + str1 string + str2 string +} + +func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" + b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" + b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" + b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" + b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" +} + +func (b *Buffer) bar() { // ERROR "leaking param: b$" + b.buf1 = b.arr[1:2] +} + +func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" + b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" + b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" +} + +func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" + b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" + b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" +} + +func (b *Buffer) bat() { // ERROR "leaking param content: b$" + o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" + o.buf1 = b.buf1[1:2] + sink = o // ERROR "o escapes to heap$" +} + +func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" + *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" + *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" +} + +type StructWithString struct { + p *int + s string +} + +// This is escape analysis false negative. +// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows +// to just x, and thus &i looks escaping. +func fieldFlowTracking() { + var x StructWithString + i := 0 // ERROR "moved to heap: i$" + x.p = &i + sink = x.s // ERROR "x.s escapes to heap$" +} + +// String operations. + +func slicebytetostring0() { + b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + _ = s +} + +func slicebytetostring1() { + b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + s1 := s[0:1] + _ = s1 +} + +func slicebytetostring2() { + b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] // ERROR "moved to heap: s1$" + sink = &s1 // ERROR "&s1 escapes to heap$" +} + +func slicebytetostring3() { + b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) escapes to heap$" + s1 := s[0:1] + sink = s1 // ERROR "s1 escapes to heap$" +} + +func addstr0() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + _ = s +} + +func addstr1() { + s0 := "a" + s1 := "b" + s := "c" + s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + _ = s +} + +func addstr2() { + b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + s0 := "a" + s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + _ = s +} + +func addstr3() { + s0 := "a" + s1 := "b" + s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" + s2 := s[0:1] + sink = s2 // ERROR "s2 escapes to heap$" +} + +func intstring0() bool { + // string does not escape + x := '0' + s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + return s == "0" +} + +func intstring1() string { + // string does not escape, but the buffer does + x := '0' + s := string(x) // ERROR "string\(x\) escapes to heap$" + return s +} + +func intstring2() { + // string escapes to heap + x := '0' + s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" + sink = &s // ERROR "&s escapes to heap$" +} + +func stringtoslicebyte0() { + s := "foo" + x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + _ = x +} + +func stringtoslicebyte1() []byte { + s := "foo" + return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicebyte2() { + s := "foo" + sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" +} + +func stringtoslicerune0() { + s := "foo" + x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + _ = x +} + +func stringtoslicerune1() []rune { + s := "foo" + return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func stringtoslicerune2() { + s := "foo" + sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" +} + +func slicerunetostring0() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" + s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + _ = s +} + +func slicerunetostring1() string { + r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + return string(r) // ERROR "string\(r\) escapes to heap$" +} + +func slicerunetostring2() { + r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + sink = string(r) // ERROR "string\(r\) escapes to heap$" +} + +func makemap0() { + m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m[0] = 0 + m[1]++ + delete(m, 1) + sink = m[0] // ERROR "m\[0\] escapes to heap$" +} + +func makemap1() map[int]int { + return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" +} + +func makemap2() { + m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" + sink = m // ERROR "m escapes to heap$" +} + +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" + return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +} + +func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" + return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +} + +func issue10353() { + x := new(int) // ERROR "new\(int\) escapes to heap$" + issue10353a(x)() +} + +func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" + return func() { // ERROR "func literal escapes to heap$" + println(*x) + } +} + +func issue10353b() { + var f func() + for { + x := new(int) // ERROR "new\(int\) escapes to heap$" + f = func() { // ERROR "func literal escapes to heap$" + println(*x) + } + } + _ = f +} + +func issue11387(x int) func() int { + f := func() int { return x } // ERROR "func literal escapes to heap" + slice1 := []func() int{f} // ERROR "\[\].* does not escape" + slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" + copy(slice2, slice1) + return slice2[0] +} + +func issue12397(x, y int) { // ERROR "moved to heap: y$" + // x does not escape below, because all relevant code is dead. + if false { + gxx = &x + } else { + gxx = &y + } + + if true { + gxx = &y + } else { + gxx = &x + } +} diff --git a/test/oldescape5.go b/test/oldescape5.go new file mode 100644 index 00000000..53d0ff80 --- /dev/null +++ b/test/oldescape5.go @@ -0,0 +1,247 @@ +// errorcheck -0 -m -l -newescape=false + +// Copyright 2012 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, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. + +package foo + +import "runtime" + +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 +} + +func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2" + return p, p +} + +func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3" + return p, q +} + +func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" + return leaktoret22(q, p) +} + +func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" + 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) + _ = p +} + +func f2() { + var x int + p := leaktoret(&x) + _ = p +} + +func f3() { + var x int // ERROR "moved to heap: x" + p := leaktoret(&x) + gp = p +} + +func f4() { + var x int // ERROR "moved to heap: x" + p, q := leaktoret2(&x) + gp = p + gp = q +} + +func f5() { + var x int + leaktoret22(leaktoret2(&x)) +} + +func f6() { + var x int // ERROR "moved to heap: x" + px1, px2 := leaktoret22(leaktoret2(&x)) + 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 +} + +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 + } + + // should make p leak always + global = p // ERROR "p escapes to heap" + return T2{p} +} + +func f9() { + var j T1 // ERROR "moved to heap: j" + f8(&j) +} + +func f10() { + // These don't escape but are too big for the stack + var x [1 << 30]byte // ERROR "moved to heap: x" + var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap" + _ = x[0] + y[0] +} + +// Test for issue 19687 (passing to unnamed parameters does not escape). +func f11(**int) { +} +func f12(_ **int) { +} +func f13() { + var x *int + f11(&x) + f12(&x) + runtime.KeepAlive(&x) // ERROR "&x does not escape" +} + +// 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() + u.N() +} + +// 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[:] + for i := range t.x[:] { + y = t.x[:] + y[i] = 1 + } + + var z *byte + for i := range t.x[:] { + z = &t.x[i] + *z = 2 + } +} + +// 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) + } + } +} + +// Issue 29000: unnamed parameter is not handled correctly + +var sink4 interface{} +var alwaysFalse = false + +func f29000(_ int, x interface{}) { // ERROR "leaking param: x" + sink4 = x + if alwaysFalse { + g29000() + } +} + +func g29000() { + x := 1 + f29000(2, x) // ERROR "x escapes to heap" +} diff --git a/test/oldescape_calls.go b/test/oldescape_calls.go new file mode 100644 index 00000000..715e8321 --- /dev/null +++ b/test/oldescape_calls.go @@ -0,0 +1,54 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 function parameters. + +// In this test almost everything is BAD except the simplest cases +// where input directly flows to output. + +package foo + +func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$" + return buf +} + +func g(*byte) string + +func h(e int) { + var x [32]byte // ERROR "moved to heap: x$" + g(&f(x[:])[0]) +} + +type Node struct { + s string + left, right *Node +} + +func walk(np **Node) int { // ERROR "leaking param content: np" + n := *np + w := len(n.s) + if n == nil { + return 0 + } + wl := walk(&n.left) + wr := walk(&n.right) + if wl < wr { + n.left, n.right = n.right, n.left + wl, wr = wr, wl + } + *np = n + return w + wl + wr +} + +// Test for bug where func var f used prototype's escape analysis results. +func prototype(xyz []string) {} // ERROR "prototype xyz does not escape" +func bar() { + var got [][]string + f := prototype + f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape" + s := "string" + f([]string{s}) // ERROR "\[\]string literal escapes to heap" +} diff --git a/test/oldescape_closure.go b/test/oldescape_closure.go new file mode 100644 index 00000000..386605df --- /dev/null +++ b/test/oldescape_closure.go @@ -0,0 +1,173 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 closure arguments. + +package escape + +var sink interface{} + +func ClosureCallArgs0() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) +} + +func ClosureCallArgs1() { + x := 0 // ERROR "moved to heap: x" + for { + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) + } +} + +func ClosureCallArgs2() { + for { + // BAD: x should not escape here + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs3() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + sink = p // ERROR "p escapes to heap" + }(&x) +} + +func ClosureCallArgs4() { + // BAD: x should not leak here + x := 0 // ERROR "moved to heap: x" + _ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + return p + }(&x) +} + +func ClosureCallArgs5() { + x := 0 // ERROR "moved to heap: x" + sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" + return p + }(&x) +} + +func ClosureCallArgs6() { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" + sink = &p // ERROR "&p escapes to heap" + }(&x) +} + +func ClosureCallArgs7() { + var pp *int + for { + x := 0 // ERROR "moved to heap: x" + func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + pp = p + }(&x) + } + _ = pp +} + +func ClosureCallArgs8() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "p does not escape" "func literal does not escape" + *p = 1 + // BAD: x should not escape to heap here + }(&x) +} + +func ClosureCallArgs9() { + // BAD: x should not leak + x := 0 // ERROR "moved to heap: x" + for { + defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs10() { + for { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" + *p = 1 + }(&x) + } +} + +func ClosureCallArgs11() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape" + sink = p // ERROR "p escapes to heap" + }(&x) +} + +func ClosureCallArgs12() { + // BAD: x should not leak + x := 0 // ERROR "moved to heap: x" + defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" + return p + }(&x) +} + +func ClosureCallArgs13() { + x := 0 // ERROR "moved to heap: x" + defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" + sink = &p // ERROR "&p escapes to heap" + }(&x) +} + +func ClosureCallArgs14() { + x := 0 // ERROR "moved to heap: x" + // BAD: &x should not escape here + p := &x // ERROR "moved to heap: p" + _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" + return *p + // BAD: p should not escape here + }(&p) +} + +func ClosureCallArgs15() { + x := 0 // ERROR "moved to heap: x" + p := &x // ERROR "moved to heap: p" + sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" + return *p + // BAD: p should not escape here + }(&p) +} + +func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + return ClosureLeak1a(t) // ERROR "ClosureLeak1 ... argument does not escape" +} + +// See #14409 -- returning part of captured var leaks it. +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return func() string { // ERROR "ClosureLeak1a func literal does not escape" + return a[0] + }() +} + +func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" + return c +} +func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" + return a[0] + }) +} +func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" + return f() +} diff --git a/test/oldescape_field.go b/test/oldescape_field.go new file mode 100644 index 00000000..e4213aaf --- /dev/null +++ b/test/oldescape_field.go @@ -0,0 +1,174 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 with respect to field assignments. + +package escape + +var sink interface{} + +type X struct { + p1 *int + p2 *int + a [2]*int +} + +type Y struct { + x X +} + +func field0() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + sink = x.p1 // ERROR "x\.p1 escapes to heap" +} + +func field1() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field3() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + sink = x // ERROR "x escapes to heap" +} + +func field4() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + sink = x // ERROR "x escapes to heap" +} + +func field5() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape here + x.a[0] = &i + 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 content: x$" + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field6a() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + field6(&x) +} + +func field7() { + i := 0 + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + _ = y1.x.p1 +} + +func field8() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap" +} + +func field9() { + i := 0 // ERROR "moved to heap: i$" + var y Y + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x // ERROR "y1\.x escapes to heap" +} + +func field10() { + i := 0 // ERROR "moved to heap: i$" + var y Y + // BAD: &i should not escape + y.x.p1 = &i + x := y.x + var y1 Y + y1.x = x + sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap" +} + +func field11() { + i := 0 // ERROR "moved to heap: i$" + x := X{p1: &i} + 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} + sink = x.p2 // ERROR "x\.p2 escapes to heap" +} + +func field13() { + i := 0 // ERROR "moved to heap: i$" + x := &X{p1: &i} // ERROR "field13 &X literal does not escape$" + 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 "field14 &X literal does not escape$" + 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$" + sink = x // ERROR "x escapes to heap" +} + +func field16() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + var iface interface{} = x // ERROR "x escapes to heap" + x1 := iface.(X) + sink = x1.p2 // ERROR "x1\.p2 escapes to heap" +} + +func field17() { + i := 0 // ERROR "moved to heap: i$" + var x X + x.p1 = &i + var iface interface{} = x // ERROR "x escapes to heap" + x1 := iface.(X) + sink = x1.p1 // ERROR "x1\.p1 escapes to heap" +} + +func field18() { + i := 0 // ERROR "moved to heap: i$" + var x X + // BAD: &i should not escape + x.p1 = &i + 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 // ERROR "y escapes to heap" +} diff --git a/test/oldescape_iface.go b/test/oldescape_iface.go new file mode 100644 index 00000000..88502df9 --- /dev/null +++ b/test/oldescape_iface.go @@ -0,0 +1,261 @@ +// errorcheck -0 -m -l -newescape=false + +// 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} + var x M = v // ERROR "v does not escape" + _ = x + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + var x M = v // ERROR "v escapes to heap" + sink = x // ERROR "x escapes to heap" + } + { + i := 0 + v := M0{&i} + var x M = v // ERROR "v does not escape" + v1 := x.(M0) + _ = v1 + } + { + i := 0 // ERROR "moved to heap: i" + v := M0{&i} + // 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} + // 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} + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := M0{&i} + 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} + var x M = v // ERROR "v does not escape" + _ = x + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + var x M = v // ERROR "v escapes to heap" + sink = x // ERROR "x escapes to heap" + } + { + i := 0 + v := M1{&i, 0} + var x M = v // ERROR "v does not escape" + v1 := x.(M1) + _ = v1 + } + { + i := 0 // ERROR "moved to heap: i" + v := M1{&i, 0} + // 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} + // 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} + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := M1{&i, 0} + 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 "&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 "&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 "&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 "&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 "&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 "&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 "&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 "&M2 literal escapes to heap" + var x M = v // ERROR "v escapes to heap" + mescapes(x) + } + { + i := 0 + v := &M2{&i} // ERROR "&M2 literal does not escape" + var x M = v // ERROR "v does not escape" + mdoesnotescape(x) + } +} + +type T1 struct { + p *int +} + +type T2 struct { + T1 T1 +} + +func dotTypeEscape() *T2 { // #11931 + var x interface{} + x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1 literal does not escape" + return &T2{ + T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap" + } +} + +func dotTypeEscape2() { // #13805, #15796 + { + i := 0 + j := 0 + var v int + var ok bool + var x interface{} = i // ERROR "i does not escape" + var y interface{} = j // ERROR "j does not escape" + + *(&v) = x.(int) + *(&v), *(&ok) = y.(int) + } + { + i := 0 + j := 0 + var ok bool + var x interface{} = i // ERROR "i does not escape" + var y interface{} = j // ERROR "j does not escape" + + sink = x.(int) // ERROR "x.\(int\) escapes to heap" + sink, *(&ok) = y.(int) + } + { + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" + var ok bool + var x interface{} = &i // ERROR "&i escapes to heap" + var y interface{} = &j // ERROR "&j escapes to heap" + + sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" + sink, *(&ok) = y.(*int) + } +} diff --git a/test/oldescape_linkname.dir/linkname1.go b/test/oldescape_linkname.dir/linkname1.go new file mode 100644 index 00000000..9c61522f --- /dev/null +++ b/test/oldescape_linkname.dir/linkname1.go @@ -0,0 +1,10 @@ +package x + +func indexByte(xs []byte, b byte) int { // ERROR "indexByte xs does not escape" + for i, x := range xs { + if x == b { + return i + } + } + return -1 +} diff --git a/test/oldescape_linkname.dir/linkname2.go b/test/oldescape_linkname.dir/linkname2.go new file mode 100644 index 00000000..5df4f50f --- /dev/null +++ b/test/oldescape_linkname.dir/linkname2.go @@ -0,0 +1,13 @@ +package y + +import _ "unsafe" + +//go:linkname byteIndex linkname1.indexByte +func byteIndex(xs []byte, b byte) int + +func ContainsSlash(data []byte) bool { // ERROR "leaking param: data" "can inline ContainsSlash" + if byteIndex(data, '/') != -1 { + return true + } + return false +} diff --git a/test/oldescape_linkname.dir/linkname3.go b/test/oldescape_linkname.dir/linkname3.go new file mode 100644 index 00000000..cbbd3a10 --- /dev/null +++ b/test/oldescape_linkname.dir/linkname3.go @@ -0,0 +1,11 @@ +package main + +import _ "./linkname1" +import "./linkname2" + +func main() { // ERROR "can inline main" + str := "hello/world" + bs := []byte(str) // ERROR "\(\[\]byte\)\(str\) escapes to heap" + if y.ContainsSlash(bs) { // ERROR "inlining call to y.ContainsSlash" + } +} diff --git a/test/oldescape_linkname.go b/test/oldescape_linkname.go new file mode 100644 index 00000000..f99df1bb --- /dev/null +++ b/test/oldescape_linkname.go @@ -0,0 +1,15 @@ +// errorcheckandrundir -0 -m -l=4 -newescape=false + +// Copyright 2010 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. + +// Tests that linknames are included in export data (issue 18167). +package ignored + +/* +Without CL 33911, this test would fail with the following error: + +main.main: relocation target linkname2.byteIndex not defined +main.main: undefined: "linkname2.byteIndex" +*/ diff --git a/test/oldescape_param.go b/test/oldescape_param.go new file mode 100644 index 00000000..3a3eee2a --- /dev/null +++ b/test/oldescape_param.go @@ -0,0 +1,441 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 function parameters. + +// In this test almost everything is BAD except the simplest cases +// where input directly flows to output. + +package escape + +func zero() int { return 0 } + +var sink interface{} + +// in -> out +func param0(p *int) *int { // ERROR "leaking param: p to result ~r1" + return p +} + +func caller0a() { + i := 0 + _ = param0(&i) +} + +func caller0b() { + i := 0 // ERROR "moved to heap: i$" + sink = param0(&i) // ERROR "param0\(&i\) escapes to heap" +} + +// in, in -> out, out +func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2" "leaking param: p2 to result ~r3" + return p1, p2 +} + +func caller1() { + i := 0 // ERROR "moved to heap: i$" + j := 0 + sink, _ = param1(&i, &j) +} + +// in -> other in +func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does not escape$" + *p2 = p1 +} + +func caller2a() { + i := 0 // ERROR "moved to heap: i$" + var p *int + param2(&i, &p) + _ = p +} + +func caller2b() { + i := 0 // ERROR "moved to heap: i$" + var p *int + param2(&i, &p) + sink = p // ERROR "p escapes to heap$" +} + +func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape" + p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]" +} + +func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p" + // Function call inside index disables self-assignment case to trigger. + p.pairs[zero()] = p.pairs[1] + p.pairs[zero()+1] = p.pairs[1] +} + +type PairOfPairs struct { + pairs [2]*Pair +} + +type BoxedPair struct { + pair *Pair +} + +type WrappedPair struct { + pair Pair +} + +func leakParam(x interface{}) { // ERROR "leaking param: x" + sink = x +} + +func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + sink = box.pair.p2 // ERROR "box.pair.p2 escapes to heap" +} + +func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + sink = box.pair // ERROR "box.pair escapes to heap" +} + +func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + leakParam(box.pair.p2) // ERROR "box.pair.p2 escapes to heap" +} + +func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" + leakParam(box.pair) // ERROR "box.pair escapes to heap" +} + +func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" + box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2" + leakParam(box2.pair.p2) // ERROR "box2.pair.p2 escapes to heap" +} + +func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" + box1.pair.p1 = box2.pair.p1 +} + +func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" + p1.pairs[0] = p2.pairs[1] +} + +func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" + p1.pairs[0].p1 = p2.pairs[1].p1 +} + +func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape" + box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" +} + +func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape" + w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2" +} + +// in -> in +type Pair struct { + p1 *int + p2 *int +} + +func param3(p *Pair) { // ERROR "param3 p does not escape" + p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2" +} + +func caller3a() { + i := 0 + j := 0 + p := Pair{&i, &j} + param3(&p) + _ = p +} + +func caller3b() { + i := 0 // ERROR "moved to heap: i$" + j := 0 // ERROR "moved to heap: j$" + p := Pair{&i, &j} + param3(&p) + sink = p // ERROR "p escapes to heap$" +} + +// in -> rcvr +func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" "leaking param: i$" + p.p1 = i +} + +func caller4a() { + i := 0 // ERROR "moved to heap: i$" + p := Pair{} + p.param4(&i) + _ = p +} + +func caller4b() { + i := 0 // ERROR "moved to heap: i$" + p := Pair{} + p.param4(&i) + sink = p // ERROR "p escapes to heap$" +} + +// in -> heap +func param5(i *int) { // ERROR "leaking param: i$" + sink = i // ERROR "i escapes to heap$" +} + +func caller5() { + i := 0 // ERROR "moved to heap: i$" + param5(&i) +} + +// *in -> heap +func param6(i ***int) { // ERROR "leaking param content: i$" + sink = *i // ERROR "\*i escapes to heap$" +} + +func caller6a() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param6(&p2) +} + +// **in -> heap +func param7(i ***int) { // ERROR "leaking param content: i$" + sink = **i // ERROR "\* \(\*i\) escapes to heap" +} + +func caller7() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + param7(&p2) +} + +// **in -> heap +func param8(i **int) { // ERROR "param8 i does not escape$" + sink = **i // ERROR "\* \(\*i\) escapes to heap" +} + +func caller8() { + i := 0 + p := &i + param8(&p) +} + +// *in -> out +func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1" + return *p +} + +func caller9a() { + i := 0 + p := &i + p2 := &p + _ = param9(&p2) +} + +func caller9b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + p2 := &p + sink = param9(&p2) // ERROR "param9\(&p2\) escapes to heap" +} + +// **in -> out +func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2" + return **p +} + +func caller10a() { + i := 0 + p := &i + p2 := &p + _ = param10(&p2) +} + +func caller10b() { + i := 0 // ERROR "moved to heap: i$" + p := &i + p2 := &p + sink = param10(&p2) // ERROR "param10\(&p2\) escapes to heap" +} + +// in escapes to heap (address of param taken and returned) +func param11(i **int) ***int { // ERROR "moved to heap: i$" + return &i +} + +func caller11a() { + i := 0 // ERROR "moved to heap: i" + p := &i // ERROR "moved to heap: p" + _ = param11(&p) +} + +func caller11b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + sink = param11(&p) // ERROR "param11\(&p\) escapes to heap" +} + +func caller11c() { // GOOD + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" + sink = *param11(&p) // ERROR "\*param11\(&p\) escapes to heap" +} + +func caller11d() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" + p2 := &p + sink = param11(p2) // ERROR "param11\(p2\) escapes to heap" +} + +// &in -> rcvr +type Indir struct { + p ***int +} + +func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$" + r.p = &i +} + +func caller12a() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + var r Indir + r.param12(&p) + _ = r +} + +func caller12b() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := &Indir{} // ERROR "caller12b &Indir literal does not escape$" + r.param12(&p) + _ = r +} + +func caller12c() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := Indir{} + r.param12(&p) + sink = r // ERROR "r escapes to heap$" +} + +func caller12d() { + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" + r := Indir{} + r.param12(&p) + sink = **r.p // ERROR "\* \(\*r\.p\) escapes to heap" +} + +// in -> value rcvr +type Val struct { + p **int +} + +func (v Val) param13(i *int) { // ERROR "Val.param13 v does not escape$" "leaking param: i$" + *v.p = i +} + +func caller13a() { + i := 0 // ERROR "moved to heap: i$" + var p *int + var v Val + v.p = &p + v.param13(&i) + _ = v +} + +func caller13b() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := Val{&p} + v.param13(&i) + _ = v +} + +func caller13c() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" + v.param13(&i) + _ = v +} + +func caller13d() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + var v Val + v.p = &p + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13e() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + v := Val{&p} + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13f() { + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" + v := &Val{&p} // ERROR "&Val literal escapes to heap$" + v.param13(&i) + sink = v // ERROR "v escapes to heap$" +} + +func caller13g() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := Val{&p} + v.param13(&i) + sink = *v.p // ERROR "\*v\.p escapes to heap" +} + +func caller13h() { + i := 0 // ERROR "moved to heap: i$" + var p *int + v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" + v.param13(&i) + sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" +} + +type Node struct { + p *Node +} + +var Sink *Node + +func f(x *Node) { // ERROR "leaking param content: x" + Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" +} + +func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0" + return &Node{x.p} // ERROR "&Node literal escapes to heap" +} + +func h(x *Node) { // ERROR "leaking param: x" + y := &Node{x} // ERROR "h &Node literal does not escape" + Sink = g(y) + f(y) +} + +// interface(in) -> out +// See also issue 29353. + +// Convert to a non-direct interface, require an allocation and +// copy x to heap (not to result). +func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" + return x // ERROR "x escapes to heap" +} + +// Convert to a direct interface, does not need an allocation. +// So x only leaks to result. +func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0" + return x // ERROR "x escapes to heap" +} diff --git a/test/oldescape_struct_return.go b/test/oldescape_struct_return.go new file mode 100644 index 00000000..5088cf86 --- /dev/null +++ b/test/oldescape_struct_return.go @@ -0,0 +1,74 @@ +// errorcheck -0 -m -l -newescape=false + +// 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 function parameters. + +package foo + +var Ssink *string + +type U struct { + _sp *string + _spp **string +} + +func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$" + return U{sp, spp} +} + +func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$" + return U{*spp, spp} +} + +func tA1() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + _ = u + println(s) +} + +func tA2() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + println(*u._sp) +} + +func tA3() { + s := "cat" + sp := &s + spp := &sp + u := A(sp, spp) + println(**u._spp) +} + +func tB1() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + _ = u + println(s) +} + +func tB2() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + println(*u._sp) +} + +func tB3() { + s := "cat" + sp := &s + spp := &sp + u := B(spp) + println(**u._spp) +} diff --git a/test/prove.go b/test/prove.go index eb0fb2a1..6e92b9ee 100644 --- a/test/prove.go +++ b/test/prove.go @@ -269,7 +269,7 @@ func f11b(a []int, i int) { func f11c(a []int, i int) { useSlice(a[:i]) - useSlice(a[:i]) // ERROR "Proved Geq64$" "Proved IsSliceInBounds$" + useSlice(a[:i]) // ERROR "Proved IsSliceInBounds$" } func f11d(a []int, i int) { @@ -469,7 +469,7 @@ func f17(b []int) { // using the derived relation between len and cap. // This depends on finding the contradiction, since we // don't query this condition directly. - useSlice(b[:i]) // ERROR "Proved Geq64$" "Proved IsSliceInBounds$" + useSlice(b[:i]) // ERROR "Proved IsSliceInBounds$" } } @@ -706,6 +706,153 @@ func range2(b [][32]int) { } } +// signhint1-2 test whether the hint (int >= 0) is propagated into the loop. +func signHint1(i int, data []byte) { + if i >= 0 { + for i < len(data) { // ERROR "Induction variable: limits \[\?,\?\), increment 1$" + _ = data[i] // ERROR "Proved IsInBounds$" + i++ + } + } +} + +func signHint2(b []byte, n int) { + if n < 0 { + panic("") + } + _ = b[25] + for i := n; i <= 25; i++ { // ERROR "Induction variable: limits \[\?,25\], increment 1$" + b[i] = 123 // ERROR "Proved IsInBounds$" + } +} + +// indexGT0 tests whether prove learns int index >= 0 from bounds check. +func indexGT0(b []byte, n int) { + _ = b[n] + _ = b[25] + + for i := n; i <= 25; i++ { // ERROR "Induction variable: limits \[\?,25\], increment 1$" + b[i] = 123 // ERROR "Proved IsInBounds$" + } +} + +// Induction variable in unrolled loop. +func unrollUpExcl(a []int) int { + var i, x int + for i = 0; i < len(a)-1; i += 2 { // ERROR "Induction variable: limits \[0,\?\), increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollUpIncl(a []int) int { + var i, x int + for i = 0; i <= len(a)-2; i += 2 { // ERROR "Induction variable: limits \[0,\?\], increment 2$" + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownExcl0(a []int) int { + var i, x int + for i = len(a) - 1; i > 0; i -= 2 { // ERROR "Induction variable: limits \(0,\?\], increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i-1] // ERROR "Proved IsInBounds$" + } + if i == 0 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownExcl1(a []int) int { + var i, x int + for i = len(a) - 1; i >= 1; i -= 2 { // ERROR "Induction variable: limits \[1,\?\], increment 2$" + x += a[i] // ERROR "Proved IsInBounds$" + x += a[i-1] // ERROR "Proved IsInBounds$" + } + if i == 0 { + x += a[i] + } + return x +} + +// Induction variable in unrolled loop. +func unrollDownInclStep(a []int) int { + var i, x int + for i = len(a); i >= 2; i -= 2 { // ERROR "Induction variable: limits \[2,\?\], increment 2$" + x += a[i-1] // ERROR "Proved IsInBounds$" + x += a[i-2] + } + if i == 1 { + x += a[i-1] + } + return x +} + +// Not an induction variable (step too large) +func unrollExclStepTooLarge(a []int) int { + var i, x int + for i = 0; i < len(a)-1; i += 3 { + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Not an induction variable (step too large) +func unrollInclStepTooLarge(a []int) int { + var i, x int + for i = 0; i <= len(a)-2; i += 3 { + x += a[i] + x += a[i+1] + } + if i == len(a)-1 { + x += a[i] + } + return x +} + +// Not an induction variable (min too small, iterating down) +func unrollDecMin(a []int) int { + var i, x int + for i = len(a); i >= math.MinInt64; i -= 2 { + x += a[i-1] + x += a[i-2] + } + if i == 1 { // ERROR "Disproved Eq64$" + x += a[i-1] + } + return x +} + +// Not an induction variable (min too small, iterating up -- perhaps could allow, but why bother?) +func unrollIncMin(a []int) int { + var i, x int + for i = len(a); i >= math.MinInt64; i += 2 { + x += a[i-1] + x += a[i-2] + } + if i == 1 { // ERROR "Disproved Eq64$" + x += a[i-1] + } + return x +} + //go:noinline func useInt(a int) { } diff --git a/test/run.go b/test/run.go index ad38d420..28ed865c 100644 --- a/test/run.go +++ b/test/run.go @@ -34,6 +34,7 @@ var ( keep = flag.Bool("k", false, "keep. keep temporary directory.") numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run") summary = flag.Bool("summary", false, "show summary of results") + allCodegen = flag.Bool("all_codegen", false, "run all goos/goarch for codegen") showSkips = flag.Bool("show_skips", false, "show skipped tests") runSkips = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)") linkshared = flag.Bool("linkshared", false, "") @@ -49,7 +50,7 @@ var ( // dirs are the directories to look for *.go files in. // TODO(bradfitz): just use all directories? - dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen"} + dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "codegen", "runtime"} // ratec controls the max number of tests running at a time. ratec chan bool @@ -233,12 +234,15 @@ func compileInDir(runcmd runCmd, dir string, flags []string, localImports bool, return runcmd(cmd...) } -func linkFile(runcmd runCmd, goname string) (err error) { +func linkFile(runcmd runCmd, goname string, ldflags []string) (err error) { pfile := strings.Replace(goname, ".go", ".o", -1) cmd := []string{goTool(), "tool", "link", "-w", "-o", "a.exe", "-L", "."} if *linkshared { cmd = append(cmd, "-linkshared", "-installsuffix=dynlink") } + if ldflags != nil { + cmd = append(cmd, ldflags...) + } cmd = append(cmd, pfile) _, err = runcmd(cmd...) return @@ -324,6 +328,18 @@ func goDirFiles(longdir string) (filter []os.FileInfo, err error) { var packageRE = regexp.MustCompile(`(?m)^package ([\p{Lu}\p{Ll}\w]+)`) +func getPackageNameFromSource(fn string) (string, error) { + data, err := ioutil.ReadFile(fn) + if err != nil { + return "", err + } + pkgname := packageRE.FindStringSubmatch(string(data)) + if pkgname == nil { + return "", fmt.Errorf("cannot find package name in %s", fn) + } + return pkgname[1], nil +} + // If singlefilepkgs is set, each file is considered a separate package // even if the package names are the same. func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) { @@ -335,19 +351,13 @@ func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) { m := make(map[string]int) for _, file := range files { name := file.Name() - data, err := ioutil.ReadFile(filepath.Join(longdir, name)) - if err != nil { - return nil, err - } - pkgname := packageRE.FindStringSubmatch(string(data)) - if pkgname == nil { - return nil, fmt.Errorf("cannot find package name in %s", name) - } - i, ok := m[pkgname[1]] + pkgname, err := getPackageNameFromSource(filepath.Join(longdir, name)) + check(err) + i, ok := m[pkgname] if singlefilepkgs || !ok { i = len(pkgs) pkgs = append(pkgs, nil) - m[pkgname[1]] = i + m[pkgname] = i } pkgs[i] = append(pkgs[i], name) } @@ -502,6 +512,7 @@ func (t *test) run() { wantError := false wantAuto := false singlefilepkgs := false + setpkgpaths := false localImports := true f := strings.Fields(action) if len(f) > 0 { @@ -511,7 +522,7 @@ func (t *test) run() { // TODO: Clean up/simplify this switch statement. switch action { - case "compile", "compiledir", "build", "builddir", "buildrundir", "run", "buildrun", "runoutput", "rundir", "asmcheck": + case "compile", "compiledir", "build", "builddir", "buildrundir", "run", "buildrun", "runoutput", "rundir", "runindir", "asmcheck": // nothing to do case "errorcheckandrundir": wantError = false // should be no error if also will run @@ -540,6 +551,8 @@ func (t *test) run() { wantError = false case "-s": singlefilepkgs = true + case "-P": + setpkgpaths = true case "-n": // Do not set relative path for local imports to current dir, // e.g. do not pass -D . -I . to the compiler. @@ -590,16 +603,19 @@ func (t *test) run() { } useTmp := true + runInDir := false runcmd := func(args ...string) ([]byte, error) { cmd := exec.Command(args[0], args[1:]...) var buf bytes.Buffer cmd.Stdout = &buf cmd.Stderr = &buf + cmd.Env = os.Environ() if useTmp { cmd.Dir = t.tempDir cmd.Env = envForDir(cmd.Dir) - } else { - cmd.Env = os.Environ() + } + if runInDir { + cmd.Dir = t.goDirName() } var err error @@ -641,13 +657,22 @@ func (t *test) run() { // Compile Go file and match the generated assembly // against a set of regexps in comments. ops := t.wantedAsmOpcodes(long) + self := runtime.GOOS + "/" + runtime.GOARCH for _, env := range ops.Envs() { + // Only run checks relevant to the current GOOS/GOARCH, + // to avoid triggering a cross-compile of the runtime. + if string(env) != self && !strings.HasPrefix(string(env), self+"/") && !*allCodegen { + continue + } // -S=2 forces outermost line numbers when disassembling inlined code. cmdline := []string{"build", "-gcflags", "-S=2"} cmdline = append(cmdline, flags...) cmdline = append(cmdline, long) cmd := exec.Command(goTool(), cmdline...) cmd.Env = append(os.Environ(), env.Environ()...) + if len(flags) > 0 && flags[0] == "-race" { + cmd.Env = append(cmd.Env, "CGO_ENABLED=1") + } var buf bytes.Buffer cmd.Stdout, cmd.Stderr = &buf, &buf @@ -765,8 +790,26 @@ func (t *test) run() { t.err = err return } + // Split flags into gcflags and ldflags + ldflags := []string{} + for i, fl := range flags { + if fl == "-ldflags" { + ldflags = flags[i+1:] + flags = flags[0:i] + break + } + } + for i, gofiles := range pkgs { - _, err := compileInDir(runcmd, longdir, flags, localImports, gofiles...) + pflags := []string{} + pflags = append(pflags, flags...) + if setpkgpaths { + fp := filepath.Join(longdir, gofiles[0]) + pkgname, serr := getPackageNameFromSource(fp) + check(serr) + pflags = append(pflags, "-p", pkgname) + } + _, err := compileInDir(runcmd, longdir, pflags, localImports, gofiles...) // Allow this package compilation fail based on conditions below; // its errors were checked in previous case. if err != nil && !(wantError && action == "errorcheckandrundir" && i == len(pkgs)-2) { @@ -774,7 +817,7 @@ func (t *test) run() { return } if i == len(pkgs)-1 { - err = linkFile(runcmd, gofiles[0]) + err = linkFile(runcmd, gofiles[0], ldflags) if err != nil { t.err = err return @@ -794,6 +837,28 @@ func (t *test) run() { } } + case "runindir": + // run "go run ." in t.goDirName() + // It's used when test requires go build and run the binary success. + // Example when long import path require (see issue29612.dir) or test + // contains assembly file (see issue15609.dir). + // Verify the expected output. + useTmp = false + runInDir = true + cmd := []string{goTool(), "run", goGcflags()} + if *linkshared { + cmd = append(cmd, "-linkshared") + } + cmd = append(cmd, ".") + out, err := runcmd(cmd...) + if err != nil { + t.err = err + return + } + if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() { + t.err = fmt.Errorf("incorrect output\n%s", out) + } + case "build": // Build Go file. _, err := runcmd(goTool(), "build", goGcflags(), "-o", "a.exe", long) @@ -1382,9 +1447,10 @@ var ( "arm64": {}, "mips": {"GOMIPS", "hardfloat", "softfloat"}, "mips64": {"GOMIPS64", "hardfloat", "softfloat"}, - "ppc64": {}, - "ppc64le": {}, + "ppc64": {"GOPPC64", "power8", "power9"}, + "ppc64le": {"GOPPC64", "power8", "power9"}, "s390x": {}, + "wasm": {}, } ) @@ -1463,6 +1529,9 @@ func (t *test) wantedAsmOpcodes(fn string) asmChecks { os, arch, subarch = "linux", archspec[0], archspec[1][1:] default: // 1 component: "386" os, arch, subarch = "linux", archspec[0], "" + if arch == "wasm" { + os = "js" + } } if _, ok := archVariants[arch]; !ok { diff --git a/test/runtime/README b/test/runtime/README new file mode 100644 index 00000000..249031af --- /dev/null +++ b/test/runtime/README @@ -0,0 +1,7 @@ +// Copyright 2019 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. + +The runtime directory contains tests that specifically need +to be compiled as-if in the runtime package. For error-check +tests, these require the additional flags -+ and -p=runtime. diff --git a/test/runtime/inlinegcpc.go b/test/runtime/inlinegcpc.go new file mode 100644 index 00000000..0943205f --- /dev/null +++ b/test/runtime/inlinegcpc.go @@ -0,0 +1,29 @@ +// errorcheck -0 -+ -p=runtime -m -newescape=true + +// Copyright 2019 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. + +package runtime + +// A function that calls runtime.getcallerpc or runtime.getcallersp() +// cannot be inlined, no matter how small it is. + +func getcallerpc() uintptr +func getcallersp() uintptr + +func pc() uintptr { + return getcallerpc() + 1 +} + +func cpc() uintptr { // ERROR "can inline cpc" + return pc() + 2 +} + +func sp() uintptr { + return getcallersp() + 3 +} + +func csp() uintptr { // ERROR "can inline csp" + return sp() + 4 +} diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go index 2c8dfd71..b8117b85 100644 --- a/test/uintptrescapes2.go +++ b/test/uintptrescapes2.go @@ -30,9 +30,9 @@ func F4(...uintptr) {} // ERROR "escaping ...uintptr" func G() { var t int // ERROR "moved to heap" - F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$" + F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" var t2 int // ERROR "moved to heap" - F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap" + F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" } func H() { diff --git a/test/writebarrier.go b/test/writebarrier.go index 8d262dd2..8cd559c1 100644 --- a/test/writebarrier.go +++ b/test/writebarrier.go @@ -261,3 +261,31 @@ func f24() **int { func f25() []string { return []string{"abc", "def", "ghi"} // no write barrier here } + +type T26 struct { + a, b, c int + d, e, f *int +} + +var g26 int + +func f26(p *int) *T26 { // see issue 29573 + return &T26{ + a: 5, + b: 6, + c: 7, + d: &g26, // no write barrier: global ptr + e: nil, // no write barrier: nil ptr + f: p, // ERROR "write barrier" + } +} + +func f27(p *int) []interface{} { + return []interface{}{ + nil, // no write barrier: zeroed memory, nil ptr + (*T26)(nil), // no write barrier: zeroed memory, type ptr & nil ptr + &g26, // no write barrier: zeroed memory, type ptr & global ptr + 7, // no write barrier: zeroed memory, type ptr & global ptr + p, // ERROR "write barrier" + } +} |