summaryrefslogtreecommitdiff
path: root/src/runtime/crash_test.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-09-19 16:33:14 -0700
committerKeith Randall <khr@golang.org>2014-09-19 16:33:14 -0700
commitad546c6d47e249174a5b339c71a39d4459161302 (patch)
tree9cd548cdb1d3d9d61d6dbc7da0afd84972479eff /src/runtime/crash_test.go
parent803001e2e76308e3c829e1a63c1f04fb042723dd (diff)
downloadgo-ad546c6d47e249174a5b339c71a39d4459161302.tar.gz
runtime: Fix interaction between Goexit and defers
When running defers, we must check whether the defer has already been marked as started so we don't run it twice. Fixes issue 8774. LGTM=rsc R=rsc CC=golang-codereviews https://codereview.appspot.com/142280044
Diffstat (limited to 'src/runtime/crash_test.go')
-rw-r--r--src/runtime/crash_test.go88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index d1577fb5f..783b4c48f 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -412,3 +412,91 @@ func main() {
runtime.Breakpoint()
}
`
+
+func TestGoexitInPanic(t *testing.T) {
+ // see issue 8774: this code used to trigger an infinite recursion
+ output := executeTest(t, goexitInPanicSource, nil)
+ want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const goexitInPanicSource = `
+package main
+import "runtime"
+func main() {
+ go func() {
+ defer func() {
+ runtime.Goexit()
+ }()
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestPanicAfterGoexit(t *testing.T) {
+ // an uncaught panic should still work after goexit
+ output := executeTest(t, panicAfterGoexitSource, nil)
+ want := "panic: hello"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const panicAfterGoexitSource = `
+package main
+import "runtime"
+func main() {
+ defer func() {
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestRecoveredPanicAfterGoexit(t *testing.T) {
+ output := executeTest(t, recoveredPanicAfterGoexitSource, nil)
+ want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+
+const recoveredPanicAfterGoexitSource = `
+package main
+import "runtime"
+func main() {
+ defer func() {
+ defer func() {
+ r := recover()
+ if r == nil {
+ panic("bad recover")
+ }
+ }()
+ panic("hello")
+ }()
+ runtime.Goexit()
+}
+`
+
+func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
+ // 1. defer a function that recovers
+ // 2. defer a function that panics
+ // 3. call goexit
+ // Goexit should run the #2 defer. Its panic
+ // should be caught by the #1 defer, and execution
+ // should resume in the caller. Like the Goexit
+ // never happened!
+ defer func() {
+ r := recover()
+ if r == nil {
+ panic("bad recover")
+ }
+ }()
+ defer func() {
+ panic("hello")
+ }()
+ runtime.Goexit()
+}