aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-06-06 22:07:32 -0400
committerRuss Cox <rsc@golang.org>2014-06-06 22:07:32 -0400
commitc70654f7e134d42f38c471f79e53a8ac83070d65 (patch)
treec934be3577012a2e4a1e35ff9ad89a70aed649e7
parente16c88a5e7b36aae7bef804d946a03af76f29960 (diff)
downloadgo-c70654f7e134d42f38c471f79e53a8ac83070d65.tar.gz
go-c70654f7e134d42f38c471f79e53a8ac83070d65.zip
[release-branch.go1.3] runtime: fix panic stack during runtime.Goexit during panic
««« CL 102220043 / 00224712f89e runtime: fix panic stack during runtime.Goexit during panic A runtime.Goexit during a panic-invoked deferred call left the panic stack intact even though all the stack frames are gone when the goroutine is torn down. The next goroutine to reuse that struct will have a bogus panic stack and can cause the traceback routines to walk into garbage. Most likely to happen during tests, because t.Fatal might be called during a deferred func and uses runtime.Goexit. This "not enough cleared in Goexit" failure mode has happened to us multiple times now. Clear all the pointers that don't make sense to keep, not just gp->panic. Fixes #8158. LGTM=iant, dvyukov R=iant, dvyukov CC=golang-codereviews https://golang.org/cl/102220043 »»» LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/108780044
-rw-r--r--src/pkg/runtime/proc.c6
-rw-r--r--test/fixedbugs/issue8158.go41
2 files changed, 47 insertions, 0 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index da2e0f9fa4..914a02e0bf 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -1459,6 +1459,12 @@ goexit0(G *gp)
gp->m = nil;
gp->lockedm = nil;
gp->paniconfault = 0;
+ gp->defer = nil; // should be true already but just in case.
+ gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
+ gp->writenbuf = 0;
+ gp->writebuf = nil;
+ gp->waitreason = nil;
+ gp->param = nil;
m->curg = nil;
m->lockedg = nil;
if(m->locked & ~LockExternal) {
diff --git a/test/fixedbugs/issue8158.go b/test/fixedbugs/issue8158.go
new file mode 100644
index 0000000000..b110de11f4
--- /dev/null
+++ b/test/fixedbugs/issue8158.go
@@ -0,0 +1,41 @@
+// run
+
+// Copyright 2014 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 (
+ "runtime"
+ "time"
+)
+
+func main() {
+ c := make(chan bool, 1)
+ go f1(c)
+ <-c
+ time.Sleep(10 * time.Millisecond)
+ go f2(c)
+ <-c
+}
+
+func f1(done chan bool) {
+ defer func() {
+ recover()
+ done <- true
+ runtime.Goexit() // left stack-allocated Panic struct on gp->panic stack
+ }()
+ panic("p")
+}
+
+func f2(done chan bool) {
+ defer func() {
+ recover()
+ done <- true
+ runtime.Goexit()
+ }()
+ time.Sleep(10 * time.Millisecond) // overwrote Panic struct with Timer struct
+ runtime.GC() // walked gp->panic list, found mangled Panic struct, crashed
+ panic("p")
+}