Skip to content

Commit 12e00f6

Browse files
cherrymuiheschi
authored andcommitted
[release-branch.go1.18] runtime: use saved LR when unwinding through morestack
On LR machine, consider F calling G calling H, which grows stack. The stack looks like ... G's frame: ... locals ... saved LR = return PC in F <- SP points here at morestack H's frame (to be created) At morestack, we save gp.sched.pc = H's morestack call gp.sched.sp = H's entry SP (the arrow above) gp.sched.lr = return PC in G Currently, when unwinding through morestack (if _TraceJumpStack is set), we switch PC and SP but not LR. We then have frame.pc = H's morestack call frame.sp = H's entry SP (the arrow above) As LR is not set, we load it from stack at *sp, so frame.lr = return PC in F As the SP hasn't decremented at the morestack call, frame.fp = frame.sp = H's entry SP Unwinding a frame, we have frame.pc = old frame.lr = return PC in F frame.sp = old frame.fp = H's entry SP a.k.a. G's SP The PC and SP don't match. The unwinding will go off if F and G have different frame sizes. Fix this by preserving the LR when switching stack. Also add code to detect infinite loop in unwinding. TODO: add some test. I can reproduce the infinite loop (or throw with added check) but the frequency is low. Fixes #53112. Updates #52116. Change-Id: I6e1294f1c6e55f664c962767a1cf6c466a0c0eff Reviewed-on: https://go-review.googlesource.com/c/go/+/400575 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Cherry Mui <[email protected]> Reviewed-by: Eric Fang <[email protected]> Reviewed-by: Benny Siegert <[email protected]> (cherry picked from commit 74f0009) Reviewed-on: https://go-review.googlesource.com/c/go/+/408821 Reviewed-by: Austin Clements <[email protected]>
1 parent 88a06f4 commit 12e00f6

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

src/runtime/traceback.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
8282
}
8383
waspanic := false
8484
cgoCtxt := gp.cgoCtxt
85+
stack := gp.stack
8586
printing := pcbuf == nil && callback == nil
8687

8788
// If the PC is zero, it's likely a nil function call.
@@ -114,7 +115,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
114115
if !f.valid() {
115116
if callback != nil || printing {
116117
print("runtime: unknown pc ", hex(frame.pc), "\n")
117-
tracebackHexdump(gp.stack, &frame, 0)
118+
tracebackHexdump(stack, &frame, 0)
118119
}
119120
if callback != nil {
120121
throw("unknown pc")
@@ -174,12 +175,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
174175
frame.fn = findfunc(frame.pc)
175176
f = frame.fn
176177
flag = f.flag
178+
frame.lr = gp.m.curg.sched.lr
177179
frame.sp = gp.m.curg.sched.sp
180+
stack = gp.m.curg.stack
178181
cgoCtxt = gp.m.curg.cgoCtxt
179182
case funcID_systemstack:
180183
// systemstack returns normally, so just follow the
181184
// stack transition.
182185
frame.sp = gp.m.curg.sched.sp
186+
stack = gp.m.curg.stack
183187
cgoCtxt = gp.m.curg.cgoCtxt
184188
flag &^= funcFlag_SPWRITE
185189
}
@@ -248,7 +252,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
248252
}
249253
if callback != nil || doPrint {
250254
print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
251-
tracebackHexdump(gp.stack, &frame, lrPtr)
255+
tracebackHexdump(stack, &frame, lrPtr)
252256
}
253257
if callback != nil {
254258
throw("unknown caller pc")
@@ -477,6 +481,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
477481
break
478482
}
479483

484+
if frame.pc == frame.lr && frame.sp == frame.fp {
485+
// If the next frame is identical to the current frame, we cannot make progress.
486+
print("runtime: traceback stuck. pc=", hex(frame.pc), " sp=", hex(frame.sp), "\n")
487+
tracebackHexdump(stack, &frame, frame.sp)
488+
throw("traceback stuck")
489+
}
490+
480491
// Unwind to next frame.
481492
frame.fn = flr
482493
frame.pc = frame.lr

0 commit comments

Comments
 (0)