]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.3] runtime: do not trace past jmpdefer during pprof traceback...
authorRuss Cox <rsc@golang.org>
Thu, 12 Jun 2014 20:55:36 +0000 (16:55 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 12 Jun 2014 20:55:36 +0000 (16:55 -0400)
««« 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 #8153

LGTM=minux, iant
R=golang-codereviews, minux, iant
CC=golang-codereviews, r
https://golang.org/cl/107970043
»»»

LGTM=r
R=golang-codereviews, r
CC=adg, golang-codereviews, iant
https://golang.org/cl/101260043

src/pkg/runtime/asm_arm.s
src/pkg/runtime/traceback_arm.c

index 024649be0769e9b6fe2df2b0ac52dcc4faebb3e6..1aea9036a78bdfe453b11aaf34760771c6d3f685 100644 (file)
@@ -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
index 8d1fc542663e07564761fe1c43cf1e0acdd72818..d15244c2a96d7c8638d969e5710dd5dcc126297e 100644 (file)
@@ -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;