diff options
author | Keith Randall <khr@golang.org> | 2019-06-05 18:42:31 +0000 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2019-06-05 19:50:09 +0000 |
commit | 49200e3f3e61f505acb152e150d054ef1db03b3e (patch) | |
tree | a0449ffcfb21af960ab9053eac39e6e42318b34e /src/runtime/traceback.go | |
parent | e9a136d185af8dcdb270096af520087c92c8b4af (diff) | |
download | go-49200e3f3e61f505acb152e150d054ef1db03b3e.tar.gz go-49200e3f3e61f505acb152e150d054ef1db03b3e.zip |
Revert "cmd/compile,runtime: allocate defer records on the stack"
This reverts commit fff4f599fe1c21e411a99de5c9b3777d06ce0ce6.
Reason for revert: Seems to still have issues around GC.
Fixes #32452
Change-Id: Ibe7af629f9ad6a3d5312acd7b066123f484da7f0
Reviewed-on: https://go-review.googlesource.com/c/go/+/180761
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r-- | src/runtime/traceback.go | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index ef48c9fa1f..d817018501 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -148,6 +148,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in waspanic := false cgoCtxt := gp.cgoCtxt printing := pcbuf == nil && callback == nil + _defer := gp._defer + + for _defer != nil && _defer.sp == _NoArgs { + _defer = _defer.link + } // If the PC is zero, it's likely a nil function call. // Start in the caller's frame. @@ -314,14 +319,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // In the latter case, use a deferreturn call site as the continuation pc. frame.continpc = frame.pc if waspanic { - if frame.fn.deferreturn != 0 { + // We match up defers with frames using the SP. + // However, if the function has an empty stack + // frame, then it's possible (on LR machines) + // for multiple call frames to have the same + // SP. But, since a function with no frame + // 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 = frame.fn.entry + uintptr(frame.fn.deferreturn) + 1 - // Note: this may perhaps keep return variables alive longer than - // strictly necessary, as we are using "function has a defer statement" - // as a proxy for "function actually deferred something". It seems - // to be a minor drawback. (We used to actually look through the - // gp._defer for a defer corresponding to this function, but that - // is hard to do with defer records on the stack during a stack copy.) // 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. @@ -330,6 +336,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } } + // Unwind our local defer stack past this frame. + for _defer != nil && ((_defer.sp == frame.sp && frame.sp != frame.fp) || _defer.sp == _NoArgs) { + _defer = _defer.link + } + if callback != nil { if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) { return n @@ -499,6 +510,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in n = nprint } + // If callback != nil, we're being called to gather stack information during + // garbage collection or stack growth. In that context, require that we used + // up the entire defer stack. If not, then there is a bug somewhere and the + // garbage collection or stack growth may not have seen the correct picture + // of the stack. Crash now instead of silently executing the garbage collection + // or stack copy incorrectly and setting up for a mysterious crash later. + // // Note that panic != nil is okay here: there can be leftover panics, // because the defers on the panic stack do not nest in frame order as // they do on the defer stack. If you have: @@ -539,6 +557,16 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in // At other times, such as when gathering a stack for a profiling signal // or when printing a traceback during a crash, everything may not be // stopped nicely, and the stack walk may not be able to complete. + // It's okay in those situations not to use up the entire defer stack: + // incomplete information then is still better than nothing. + if callback != nil && n < max && _defer != nil { + print("runtime: g", gp.goid, ": leftover defer sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n") + for _defer = gp._defer; _defer != nil; _defer = _defer.link { + print("\tdefer ", _defer, " sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n") + } + throw("traceback has leftover defers") + } + if callback != nil && n < max && frame.sp != gp.stktopsp { print("runtime: g", gp.goid, ": frame.sp=", hex(frame.sp), " top=", hex(gp.stktopsp), "\n") print("\tstack=[", hex(gp.stack.lo), "-", hex(gp.stack.hi), "] n=", n, " max=", max, "\n") |