]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: clear frame pointer in mcall
authorMichael Pratt <mpratt@google.com>
Fri, 2 May 2025 18:18:03 +0000 (14:18 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 2 May 2025 20:11:15 +0000 (13:11 -0700)
On amd64, mcall leaves BP untouched, so the callback will push BP,
connecting the g0 stack to the calling g stack. This seems OK (frame
pointer unwinders like Linux perf can see what user code called into the
scheduler), but the "scheduler" part is problematic.

mcall is used when calling into the scheduler to deschedule the current
goroutine (e.g., in goyield). Once the goroutine is descheduled, it may
be picked up by another M and continue execution. The other thread is
mutating the goroutine stack, but our M still has a frame pointer
pointing to the goroutine stack.

A frame pointer unwinder like Linux perf could get bogus values off of
the mutating stack. Note that though the execution tracer uses
framepointer unwinding, it never unwinds a g0, so it isn't affected.

Clear the frame pointer in mcall so that unwinding always stops at
mcall.

On arm64, mcall stores the frame pointer from g0.sched.bp. This doesn't
really make any sense. mcall wasn't called by whatever used g0 last, so
at best unwinding will get misleading results (e.g., it might look like
cgocallback calls mcall?).

Also clear the frame pointer on arm64.

Other architectures don't use frame pointers.

For #63630.

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-linux-arm64-longtest
Change-Id: I6a6a636cb6404f3c95ecabdb969c9b8184615cee
Reviewed-on: https://go-review.googlesource.com/c/go/+/669615
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nick Ripley <nick.ripley@datadoghq.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>

src/runtime/asm_amd64.s
src/runtime/asm_arm64.s

index 9c262a7ce8703640ccd52d27431048841015c54b..14e2ea6686c5f4dc0ca0e429cd11bd6a24b84803 100644 (file)
@@ -452,6 +452,7 @@ goodm:
        get_tls(CX)             // Set G in TLS
        MOVQ    R14, g(CX)
        MOVQ    (g_sched+gobuf_sp)(R14), SP     // sp = g0.sched.sp
+       MOVQ    $0, BP  // clear frame pointer, as caller may execute on another M
        PUSHQ   AX      // open up space for fn's arg spill slot
        MOVQ    0(DX), R12
        CALL    R12             // fn(g)
index 6c447ac23c93a78a87a03b76f93fe247452b5102..18d2dc5d57cb5e03f4aa0612e18acc897b2d5294 100644 (file)
@@ -233,7 +233,7 @@ TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT|NOFRAME, $0-8
 
        MOVD    (g_sched+gobuf_sp)(g), R0
        MOVD    R0, RSP // sp = m->g0->sched.sp
-       MOVD    (g_sched+gobuf_bp)(g), R29
+       MOVD    $0, R29                         // clear frame pointer, as caller may execute on another M
        MOVD    R3, R0                          // arg = g
        MOVD    $0, -16(RSP)                    // dummy LR
        SUB     $16, RSP