Skip to content

Commit 2380d17

Browse files
felixgecherrymuimknyszeknsrip-dd
committed
runtime: fix systemstack frame pointer adjustment
Change adjustframe to adjust the frame pointer of systemstack (aka FuncID_systemstack_switch) before returning early. Without this fix it is possible for traceEvent() to crash when using frame pointer unwinding. The issue occurs when a goroutine calls systemstack in order to call shrinkstack. While returning, systemstack will restore the unadjusted frame pointer from its frame as part of its epilogue. If the callee of systemstack then triggers a traceEvent, it will try to unwind into the old stack. This can lead to a crash if the memory of the old stack has been reused or freed in the meantime. The most common situation in which this will manifest is when when gcAssistAlloc() invokes gcAssistAlloc1() on systemstack() and performs a shrinkstack() followed by a traceGCMarkAssistDone() or Gosched() triggering traceEvent(). See CL 489115 for a deterministic test case that triggers the issue. Meanwhile the problem can frequently be observed using the command below: $ GODEBUG=tracefpunwindoff=0 ../bin/go test -trace /dev/null -run TestDeferHeapAndStack ./runtime SIGSEGV: segmentation violation PC=0x45f977 m=14 sigcode=128 goroutine 0 [idle]: runtime.fpTracebackPCs(...) .../go/src/runtime/trace.go:945 runtime.traceStackID(0xcdab904677a?, {0x7f1584346018, 0x0?, 0x80}, 0x0?) .../go/src/runtime/trace.go:917 +0x217 fp=0x7f1565ffab00 sp=0x7f1565ffaab8 pc=0x45f977 runtime.traceEventLocked(0x0?, 0x0?, 0x0?, 0xc00003dbd0, 0x12, 0x0, 0x1, {0x0, 0x0, 0x0}) .../go/src/runtime/trace.go:760 +0x285 fp=0x7f1565ffab78 sp=0x7f1565ffab00 pc=0x45ef45 runtime.traceEvent(0xf5?, 0x1, {0x0, 0x0, 0x0}) .../go/src/runtime/trace.go:692 +0xa9 fp=0x7f1565ffabe0 sp=0x7f1565ffab78 pc=0x45ec49 runtime.traceGoPreempt(...) .../go/src/runtime/trace.go:1535 runtime.gopreempt_m(0xc000328340?) .../go/src/runtime/proc.go:3551 +0x45 fp=0x7f1565ffac20 sp=0x7f1565ffabe0 pc=0x4449a5 runtime.newstack() .../go/src/runtime/stack.go:1077 +0x3cb fp=0x7f1565ffadd0 sp=0x7f1565ffac20 pc=0x455feb runtime.morestack() .../go/src/runtime/asm_amd64.s:593 +0x8f fp=0x7f1565ffadd8 sp=0x7f1565ffadd0 pc=0x47644f goroutine 19 [running]: runtime.traceEvent(0x2c?, 0xffffffffffffffff, {0x0, 0x0, 0x0}) .../go/src/runtime/trace.go:669 +0xe8 fp=0xc0006e6c28 sp=0xc0006e6c20 pc=0x45ec88 runtime.traceGCMarkAssistDone(...) .../go/src/runtime/trace.go:1497 runtime.gcAssistAlloc(0xc0003281a0) .../go/src/runtime/mgcmark.go:517 +0x27d fp=0xc0006e6c88 sp=0xc0006e6c28 pc=0x421a1d runtime.deductAssistCredit(0x0?) .../go/src/runtime/malloc.go:1287 +0x54 fp=0xc0006e6cb0 sp=0xc0006e6c88 pc=0x40fed4 runtime.mallocgc(0x400, 0x7a9420, 0x1) .../go/src/runtime/malloc.go:1002 +0xc9 fp=0xc0006e6d18 sp=0xc0006e6cb0 pc=0x40f709 runtime.newobject(0xb3?) .../go/src/runtime/malloc.go:1324 +0x25 fp=0xc0006e6d40 sp=0xc0006e6d18 pc=0x40ffc5 runtime_test.deferHeapAndStack(0xb4) .../go/src/runtime/stack_test.go:924 +0x165 fp=0xc0006e6e20 sp=0xc0006e6d40 pc=0x75c2a5 Fixes #59692 Co-Authored-By: Cherry Mui <[email protected]> Co-Authored-By: Michael Knyszek <[email protected]> Co-Authored-By: Nick Ripley <[email protected]> Change-Id: I1c0c28327fc2fac0b8cfdbaa72e25584331be31e Reviewed-on: https://go-review.googlesource.com/c/go/+/489015 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Run-TryBot: Felix Geisendörfer <[email protected]>
1 parent 4b66502 commit 2380d17

File tree

1 file changed

+15
-14
lines changed

1 file changed

+15
-14
lines changed

src/runtime/stack.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -650,20 +650,6 @@ func adjustframe(frame *stkframe, adjinfo *adjustinfo) {
650650
if stackDebug >= 2 {
651651
print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
652652
}
653-
if f.funcID == abi.FuncID_systemstack_switch {
654-
// A special routine at the bottom of stack of a goroutine that does a systemstack call.
655-
// We will allow it to be copied even though we don't
656-
// have full GC info for it (because it is written in asm).
657-
return
658-
}
659-
660-
locals, args, objs := frame.getStackMap(&adjinfo.cache, true)
661-
662-
// Adjust local variables if stack frame has been allocated.
663-
if locals.n > 0 {
664-
size := uintptr(locals.n) * goarch.PtrSize
665-
adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f)
666-
}
667653

668654
// Adjust saved frame pointer if there is one.
669655
if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize {
@@ -687,6 +673,21 @@ func adjustframe(frame *stkframe, adjinfo *adjustinfo) {
687673
adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
688674
}
689675

676+
if f.funcID == abi.FuncID_systemstack_switch {
677+
// A special routine at the bottom of stack of a goroutine that does a systemstack call.
678+
// We will allow it to be copied even though we don't
679+
// have full GC info for it (because it is written in asm).
680+
return
681+
}
682+
683+
locals, args, objs := frame.getStackMap(&adjinfo.cache, true)
684+
685+
// Adjust local variables if stack frame has been allocated.
686+
if locals.n > 0 {
687+
size := uintptr(locals.n) * goarch.PtrSize
688+
adjustpointers(unsafe.Pointer(frame.varp-size), &locals, adjinfo, f)
689+
}
690+
690691
// Adjust arguments.
691692
if args.n > 0 {
692693
if stackDebug >= 3 {

0 commit comments

Comments
 (0)