Skip to content

Commit 265d19e

Browse files
nsrip-ddgopherbot
authored andcommitted
runtime/trace: avoid frame pointer unwinding for events during cgocallbackg
The current mp.incgocallback() logic allows for trace events to be recorded using frame pointer unwinding during cgocallbackg when they shouldn't be. Specifically, mp.incgo will be false during the reentersyscall call at the end. It's possible to crash with tracing enabled because of this, if C code which uses the frame pointer register for other purposes calls into Go. This can be seen, for example, by forcing testprogcgo/trace_unix.c to write a garbage value to RBP prior to calling into Go. We can drop the mp.incgo check, and instead conservatively avoid doing frame pointer unwinding if there is any C on the stack. This is the case if mp.ncgo > 0, or if mp.isextra is true (meaning we're coming from a thread created by C). Rename incgocallback to reflect that we're checking if there's any C on the stack. We can also move the ncgo increment in cgocall closer to where the transition to C happens, which lets us use frame pointer unwinding for the entersyscall event during the first Go-to-C call on a stack, when there isn't yet any C on the stack. Fixes #59830. Change-Id: If178a705a9d38d0d2fb19589a9e669cd982d32cd Reviewed-on: https://go-review.googlesource.com/c/go/+/488755 Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Felix Geisendörfer <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> Run-TryBot: Nick Ripley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 0fd6ae5 commit 265d19e

File tree

3 files changed

+12
-5
lines changed

3 files changed

+12
-5
lines changed

src/runtime/cgocall.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
136136

137137
mp := getg().m
138138
mp.ncgocall++
139-
mp.ncgo++
140139

141140
// Reset traceback.
142141
mp.cgoCallers[0] = 0
@@ -165,6 +164,14 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
165164
osPreemptExtEnter(mp)
166165

167166
mp.incgo = true
167+
// We use ncgo as a check during execution tracing for whether there is
168+
// any C on the call stack, which there will be after this point. If
169+
// there isn't, we can use frame pointer unwinding to collect call
170+
// stacks efficiently. This will be the case for the first Go-to-C call
171+
// on a stack, so it's prefereable to update it here, after we emit a
172+
// trace event in entersyscall above.
173+
mp.ncgo++
174+
168175
errno := asmcgocall(fn, arg)
169176

170177
// Update accounting before exitsyscall because exitsyscall may

src/runtime/proc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -868,8 +868,8 @@ func (mp *m) becomeSpinning() {
868868
sched.needspinning.Store(0)
869869
}
870870

871-
func (mp *m) incgocallback() bool {
872-
return (!mp.incgo && mp.ncgo > 0) || mp.isextra
871+
func (mp *m) hasCgoOnStack() bool {
872+
return mp.ncgo > 0 || mp.isextra
873873
}
874874

875875
var fastrandseed uintptr

src/runtime/trace.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -889,10 +889,10 @@ func traceStackID(mp *m, pcBuf []uintptr, skip int) uint64 {
889889
gp := getg()
890890
curgp := mp.curg
891891
nstk := 1
892-
if tracefpunwindoff() || mp.incgocallback() {
892+
if tracefpunwindoff() || mp.hasCgoOnStack() {
893893
// Slow path: Unwind using default unwinder. Used when frame pointer
894894
// unwinding is unavailable or disabled (tracefpunwindoff), or might
895-
// produce incomplete results or crashes (incgocallback). Note that no
895+
// produce incomplete results or crashes (hasCgoOnStack). Note that no
896896
// cgo callback related crashes have been observed yet. The main
897897
// motivation is to take advantage of a potentially registered cgo
898898
// symbolizer.

0 commit comments

Comments
 (0)