diff options
| author | Keith Randall <khr@golang.org> | 2014-09-19 16:33:14 -0700 |
|---|---|---|
| committer | Keith Randall <khr@golang.org> | 2014-09-19 16:33:14 -0700 |
| commit | 0306478fe57767530164b43c12969ca91496db47 (patch) | |
| tree | 7c3210abe0211520437172cc124d67146d4b4344 /src/runtime/panic.go | |
| parent | 651bb8e026f94502ed45db1b6284eeddd74570dc (diff) | |
| download | go-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.go | 18 |
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 |
