Skip to content

Commit a8e839b

Browse files
committed
[release-branch.go1.5] runtime: make SIGPROF skip stacks that are being copied
sigprof tracebacks the stack across systemstack switches to make profile tracebacks more complete. However, it does this even if the user stack is currently being copied, which means it may be in an inconsistent state that will cause the traceback to panic. One specific way this can happen is during stack shrinking. Some goroutine blocks for STW, then enters gchelper, which then assists with root marking. If that root marking happens to pick the original goroutine and its stack needs to be shrunk, it will begin to copy that stack. During this copy, the stack is generally inconsistent and, in particular, the actual locations of the stack barriers and their recorded locations are temporarily out of sync. If a SIGPROF happens during this inconsistency, it will walk the stack all the way back to the blocked goroutine and panic when it fails to unwind the stack barriers. Fix this by disallowing jumping to the user stack during SIGPROF if that user stack is in the process of being copied. Fixes #12932. Change-Id: I9ef694c2c01e3653e292ce22612418dd3daff1b4 Reviewed-on: https://go-review.googlesource.com/16819 Reviewed-by: Daniel Morsing <[email protected]> Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-on: https://go-review.googlesource.com/16985 Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Russ Cox <[email protected]>
1 parent ecb9ce6 commit a8e839b

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

src/runtime/proc1.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -2582,7 +2582,14 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
25822582
// This is especially important on windows, since all syscalls are cgo calls.
25832583
n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0)
25842584
} else if traceback {
2585-
n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
2585+
flags := uint(_TraceTrap | _TraceJumpStack)
2586+
if gp.m.curg != nil && readgstatus(gp.m.curg) == _Gcopystack {
2587+
// We can traceback the system stack, but
2588+
// don't jump to the potentially inconsistent
2589+
// user stack.
2590+
flags &^= _TraceJumpStack
2591+
}
2592+
n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, flags)
25862593
}
25872594
if !traceback || n <= 0 {
25882595
// Normal traceback is impossible or has failed.

0 commit comments

Comments
 (0)