Skip to content

Commit f7a87e3

Browse files
committed
runtime: fix bp restoration in panic recovery for arm64
Previously, the frame pointer wouldn't be restored at all, which could cause panics during frame pointer unwinding. As of CL 516157, the frame pointer is restored, but it's restored incorrectly on arm64: on arm64, the frame pointer points one word below SP, but here it's one below panic.fp which is the stack pointer of the caller's frame (nothing to do with the architectural bp). For #61766. Change-Id: I86504b85a4d741df5939b51c914d9e7c8d6edaad Reviewed-on: https://go-review.googlesource.com/c/go/+/523697 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 38db2df commit f7a87e3

File tree

2 files changed

+20
-14
lines changed

2 files changed

+20
-14
lines changed

src/runtime/callers_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ func TestFPUnwindAfterRecovery(t *testing.T) {
478478
pcs[i] = 10
479479
}
480480
runtime.FPCallers(pcs)
481+
t.Logf("%v", pcs)
481482
}()
482483
defer func() {
483484
if recover() == nil {

src/runtime/panic.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,10 @@ func deferproc(fn func()) {
313313
// The g._defer list is now a linked list of deferred calls,
314314
// but an atomic list hanging off:
315315
//
316-
// g._defer => d4 -> d3 -> drangefunc -> d2 -> d1 -> nil
317-
// | .head
318-
// |
319-
// +--> dY -> dX -> nil
316+
// g._defer => d4 -> d3 -> drangefunc -> d2 -> d1 -> nil
317+
// | .head
318+
// |
319+
// +--> dY -> dX -> nil
320320
//
321321
// with each -> indicating a d.link pointer, and where drangefunc
322322
// has the d.rangefunc = true bit set.
@@ -340,10 +340,10 @@ func deferproc(fn func()) {
340340
//
341341
// That is, deferconvert changes this list:
342342
//
343-
// g._defer => drangefunc -> d2 -> d1 -> nil
344-
// | .head
345-
// |
346-
// +--> dY -> dX -> nil
343+
// g._defer => drangefunc -> d2 -> d1 -> nil
344+
// | .head
345+
// |
346+
// +--> dY -> dX -> nil
347347
//
348348
// into this list:
349349
//
@@ -1149,15 +1149,20 @@ func recovery(gp *g) {
11491149
gp.sched.sp = sp
11501150
gp.sched.pc = pc
11511151
gp.sched.lr = 0
1152-
// fp points to the stack pointer at the caller, which is the top of the
1153-
// stack frame. The frame pointer used for unwinding is the word
1154-
// immediately below it.
1155-
gp.sched.bp = fp - goarch.PtrSize
1156-
if !usesLR {
1152+
// Restore the bp on platforms that support frame pointers.
1153+
// N.B. It's fine to not set anything for platforms that don't
1154+
// support frame pointers, since nothing consumes them.
1155+
switch {
1156+
case goarch.IsAmd64 != 0:
11571157
// on x86, fp actually points one word higher than the top of
11581158
// the frame since the return address is saved on the stack by
11591159
// the caller
1160-
gp.sched.bp -= goarch.PtrSize
1160+
gp.sched.bp = fp - 2*goarch.PtrSize
1161+
case goarch.IsArm64 != 0:
1162+
// on arm64, the architectural bp points one word higher
1163+
// than the sp. fp is totally useless to us here, because it
1164+
// only gets us to the caller's fp.
1165+
gp.sched.bp = sp - goarch.PtrSize
11611166
}
11621167
gp.sched.ret = 1
11631168
gogo(&gp.sched)

0 commit comments

Comments
 (0)