summaryrefslogtreecommitdiff
path: root/src/runtime/defer_test.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2019-10-09 12:18:26 -0700
committerDan Scales <danscales@google.com>2019-11-04 16:32:38 +0000
commit7dcd343ed641d3b70c09153d3b041ca3fe83b25e (patch)
tree78f84bf2886ea89ea9a292630fff54bcefdbd985 /src/runtime/defer_test.go
parenta8fc82f77abff99a3f55b015b017cb4342cd9c08 (diff)
downloadgo-git-7dcd343ed641d3b70c09153d3b041ca3fe83b25e.tar.gz
runtime: ensure that Goexit cannot be aborted by a recursive panic/recover
When we do a successful recover of a panic, we resume normal execution by returning from the frame that had the deferred call that did the recover (after executing any remaining deferred calls in that frame). However, suppose we have called runtime.Goexit and there is a panic during one of the deferred calls run by the Goexit. Further assume that there is a deferred call in the frame of the Goexit or a parent frame that does a recover. Then the recovery process will actually resume normal execution above the Goexit frame and hence abort the Goexit. We will not terminate the thread as expected, but continue running in the frame above the Goexit. To fix this, we explicitly create a _panic object for a Goexit call. We then change the "abort" behavior for Goexits, but not panics. After a recovery, if the top-level panic is actually a Goexit that is marked to be aborted, then we return to the Goexit defer-processing loop, so that the Goexit is not actually aborted. Actual code changes are just panic.go, runtime2.go, and funcid.go. Adjusted the test related to the new Goexit behavior (TestRecoverBeforePanicAfterGoexit) and added several new tests of aborted panics (whose behavior has not changed). Fixes #29226 Change-Id: Ib13cb0074f5acc2567a28db7ca6912cfc47eecb5 Reviewed-on: https://go-review.googlesource.com/c/go/+/200081 Run-TryBot: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/defer_test.go')
-rw-r--r--src/runtime/defer_test.go14
1 files changed, 6 insertions, 8 deletions
diff --git a/src/runtime/defer_test.go b/src/runtime/defer_test.go
index f03bdb47d5..51cd4bb9cc 100644
--- a/src/runtime/defer_test.go
+++ b/src/runtime/defer_test.go
@@ -121,18 +121,16 @@ func TestDisappearingDefer(t *testing.T) {
}
// This tests an extra recursive panic behavior that is only specified in the
-// code. Suppose a first panic P1 happens and starts processing defer calls. If
-// a second panic P2 happens while processing defer call D in frame F, then defer
+// code. Suppose a first panic P1 happens and starts processing defer calls. If a
+// second panic P2 happens while processing defer call D in frame F, then defer
// call processing is restarted (with some potentially new defer calls created by
-// D or its callees). If the defer processing reaches the started defer call D
+// D or its callees). If the defer processing reaches the started defer call D
// again in the defer stack, then the original panic P1 is aborted and cannot
-// continue panic processing or be recovered. If the panic P2 does a recover at
-// some point, it will naturally the original panic P1 from the stack, since the
-// original panic had to be in frame F or a descendant of F.
+// continue panic processing or be recovered. If the panic P2 does a recover at
+// some point, it will naturally remove the original panic P1 from the stack
+// (since the original panic had to be in frame F or a descendant of F).
func TestAbortedPanic(t *testing.T) {
defer func() {
- // The first panic should have been "aborted", so there is
- // no other panic to recover
r := recover()
if r != nil {
t.Fatal(fmt.Sprintf("wanted nil recover, got %v", r))