aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/panic.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
commit0306478fe57767530164b43c12969ca91496db47 (patch)
tree7c3210abe0211520437172cc124d67146d4b4344 /src/runtime/panic.go
parent651bb8e026f94502ed45db1b6284eeddd74570dc (diff)
downloadgo-0306478fe57767530164b43c12969ca91496db47.tar.xz
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 #8774. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/142280044
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go18
1 files changed, 17 insertions, 1 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 3cc31053e8..7eb2d6055a 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -247,11 +247,27 @@ func deferreturn(arg0 uintptr) {
// If all other goroutines exit, the program crashes.
func Goexit() {
// Run all deferred functions for the current goroutine.
+ // This code is similar to gopanic, see that implementation
+ // for detailed comments.
gp := getg()
- for gp._defer != nil {
+ for {
d := gp._defer
+ if d == nil {
+ break
+ }
+ if d.started {
+ if d._panic != nil {
+ d._panic.aborted = true
+ }
+ gp._defer = d.link
+ freedefer(d)
+ continue
+ }
d.started = true
reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+ if gp._defer != d {
+ gothrow("bad defer entry in Goexit")
+ }
gp._defer = d.link
freedefer(d)
// Note: we ignore recovers here because Goexit isn't a panic