diff options
author | Russ Cox <rsc@golang.org> | 2014-06-12 16:55:36 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-06-12 16:55:36 -0400 |
commit | 6f415ce6c0a84a6b0f3f154102ffe0542a54250e (patch) | |
tree | fa387584489678b3359f71b7e541dfbbd7a9127b | |
parent | 84dd645ab3c9b914f7a8dea1e817f0cc65f34a51 (diff) | |
download | go-6f415ce6c0a84a6b0f3f154102ffe0542a54250e.tar.gz |
[release-branch.go1.3] runtime: do not trace past jmpdefer during pprof traceback on arm
??? CL 107970043 / b336da131a84
runtime: do not trace past jmpdefer during pprof traceback on arm
jmpdefer modifies PC, SP, and LR, and not atomically,
so walking past jmpdefer will often end up in a state
where the three are not a consistent execution snapshot.
This was causing warning messages a few frames later
when the traceback realized it was confused, but given
the right memory it could easily crash instead.
Update issue 8153
LGTM=minux, iant
R=golang-codereviews, minux, iant
CC=golang-codereviews, r
https://codereview.appspot.com/107970043
???
LGTM=r
R=golang-codereviews, r
CC=adg, golang-codereviews, iant
https://codereview.appspot.com/101260043
-rw-r--r-- | src/pkg/runtime/asm_arm.s | 4 | ||||
-rw-r--r-- | src/pkg/runtime/traceback_arm.c | 13 |
2 files changed, 17 insertions, 0 deletions
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s index 024649be0..1aea9036a 100644 --- a/src/pkg/runtime/asm_arm.s +++ b/src/pkg/runtime/asm_arm.s @@ -394,6 +394,10 @@ TEXT runtime·lessstack(SB), NOSPLIT, $-4-0 // 1. grab stored LR for caller // 2. sub 4 bytes to get back to BL deferreturn // 3. B to fn +// TODO(rsc): Push things on stack and then use pop +// to load all registers simultaneously, so that a profiling +// interrupt can never see mismatched SP/LR/PC. +// (And double-check that pop is atomic in that way.) TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8 MOVW 0(SP), LR MOVW $-4(LR), LR // BL deferreturn diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c index 8d1fc5426..d15244c2a 100644 --- a/src/pkg/runtime/traceback_arm.c +++ b/src/pkg/runtime/traceback_arm.c @@ -110,6 +110,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, if(runtime·topofstack(f)) { frame.lr = 0; flr = nil; + } else if(f->entry == (uintptr)runtime·jmpdefer) { + // jmpdefer modifies SP/LR/PC non-atomically. + // If a profiling interrupt arrives during jmpdefer, + // the stack unwind may see a mismatched register set + // and get confused. Stop if we see PC within jmpdefer + // to avoid that confusion. + // See golang.org/issue/8153. + // This check can be deleted if jmpdefer is changed + // to restore all three atomically using pop. + if(callback != nil) + runtime·throw("traceback_arm: found jmpdefer when tracing with callback"); + frame.lr = 0; + flr = nil; } else { if((n == 0 && frame.sp < frame.fp) || frame.lr == 0) frame.lr = *(uintptr*)frame.sp; |