aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2020-08-08 07:58:04 -0700
committerDmitri Shuralyov <dmitshur@golang.org>2020-10-05 23:01:35 +0000
commit0893e6a43736a946d78e50e7422b457eb9ca9984 (patch)
tree62290565a3ad3386eff9aeaa0a30d615a044bda7 /test
parentc25dd3f8325a5022a2573c71afd810f3fb604b08 (diff)
downloadgo-0893e6a43736a946d78e50e7422b457eb9ca9984.tar.gz
go-0893e6a43736a946d78e50e7422b457eb9ca9984.zip
[release-branch.go1.15] cmd/compile: fix live variable computation for deferreturn
Taking the live variable set from the last return point is problematic. See #40629 for details, but there may not be a return point, or it may be before the final defer. Additionally, keeping track of the last call as a *Value doesn't quite work. If it is dead-code eliminated, the storage for the Value is reused for some other random instruction. Its live variable information, if it is available at all, is wrong. Instead, just mark all the open-defer argument slots as live throughout the function. (They are already zero-initialized.) Fixes #40742 Change-Id: Ie456c7db3082d0de57eaa5234a0f32525a1cce13 Reviewed-on: https://go-review.googlesource.com/c/go/+/247522 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com> (cherry picked from commit 32a84c99e136ed5af0686dbedd31fd7dff40fb38) Reviewed-on: https://go-review.googlesource.com/c/go/+/248621 Trust: Dmitri Shuralyov <dmitshur@golang.org>
Diffstat (limited to 'test')
-rw-r--r--test/fixedbugs/issue40629.go69
1 files changed, 69 insertions, 0 deletions
diff --git a/test/fixedbugs/issue40629.go b/test/fixedbugs/issue40629.go
new file mode 100644
index 00000000000..c6ef408f494
--- /dev/null
+++ b/test/fixedbugs/issue40629.go
@@ -0,0 +1,69 @@
+// run
+
+// Copyright 2020 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"
+
+const N = 40
+
+func main() {
+ var x [N]int // stack-allocated memory
+ for i := range x {
+ x[i] = 0x999
+ }
+
+ // This defer checks to see if x is uncorrupted.
+ defer func(p *[N]int) {
+ recover()
+ for i := range p {
+ if p[i] != 0x999 {
+ for j := range p {
+ fmt.Printf("p[%d]=0x%x\n", j, p[j])
+ }
+ panic("corrupted stack variable")
+ }
+ }
+ }(&x)
+
+ // This defer starts a new goroutine, which will (hopefully)
+ // overwrite x on the garbage stack.
+ defer func() {
+ c := make(chan bool)
+ go func() {
+ useStack(1000)
+ c <- true
+ }()
+ <-c
+
+ }()
+
+ // This defer causes a stack copy.
+ // The old stack is now garbage.
+ defer func() {
+ useStack(1000)
+ }()
+
+ // Trigger a segfault.
+ *g = 0
+
+ // Make the return statement unreachable.
+ // That makes the stack map at the deferreturn call empty.
+ // In particular, the argument to the first defer is not
+ // marked as a pointer, so it doesn't get adjusted
+ // during the stack copy.
+ for {
+ }
+}
+
+var g *int64
+
+func useStack(n int) {
+ if n == 0 {
+ return
+ }
+ useStack(n - 1)
+}