aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
authorKeith Randall <keithr@alum.mit.edu>2018-09-11 15:14:28 -0700
committerKeith Randall <khr@golang.org>2018-10-03 19:54:23 +0000
commit9dac0a8132d7db5225b27bdd8faeb3158e624159 (patch)
treef2d0d9f80bc5f7101fc06c1d13d719fbd663533b /src/runtime/traceback.go
parent9a8372f8bd5a39d2476bfa9247407b51f9193b9e (diff)
downloadgo-9dac0a8132d7db5225b27bdd8faeb3158e624159.tar.gz
go-9dac0a8132d7db5225b27bdd8faeb3158e624159.zip
runtime: on a signal, set traceback address to a deferreturn call
When a function triggers a signal (like a segfault which translates to a nil pointer exception) during execution, a sigpanic handler is just below it on the stack. The function itself did not stop at a safepoint, so we have to figure out what safepoint we should use to scan its stack frame. Previously we used the site of the most recent defer to get the live variables at the signal site. That answer is not quite correct, as explained in #27518. Instead, use the site of a deferreturn call. It has all the right variables marked as live (no args, all the return values, except those that escape to the heap, in which case the corresponding PAUTOHEAP variables will be live instead). This CL requires stack objects, so that all the local variables and args referenced by the deferred closures keep the right variables alive. Fixes #27518 Change-Id: Id45d8a8666759986c203181090b962e2981e48ca Reviewed-on: https://go-review.googlesource.com/c/134637 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r--src/runtime/traceback.go8
1 files changed, 5 insertions, 3 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 69d5764c8f7..d7265b2bb94 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -312,8 +312,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// the function either doesn't return at all (if it has no defers or if the
// defers do not recover) or it returns from one of the calls to
// deferproc a second time (if the corresponding deferred func recovers).
- // It suffices to assume that the most recent deferproc is the one that
- // returns; everything live at earlier deferprocs is still live at that one.
+ // In the latter case, use a deferreturn call site as the continuation pc.
frame.continpc = frame.pc
if waspanic {
// We match up defers with frames using the SP.
@@ -324,7 +323,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// can't push a defer, the defer can't belong
// to that frame.
if _defer != nil && _defer.sp == frame.sp && frame.sp != frame.fp {
- frame.continpc = _defer.pc
+ frame.continpc = frame.fn.entry + uintptr(frame.fn.deferreturn) + 1
+ // Note: the +1 is to offset the -1 that
+ // stack.go:getStackMap does to back up a return
+ // address make sure the pc is in the CALL instruction.
} else {
frame.continpc = 0
}