Skip to content

Commit

Permalink
1.21_linux/runtime: bug fix: crash with 'morestack on g0'
Browse files Browse the repository at this point in the history
This change applies https://go-review.googlesource.com/c/go/+/527715
to fix the crash (morestack on g0) in some special environments.
  • Loading branch information
hajimehoshi committed Sep 20, 2023
1 parent eeb89f1 commit 02e7122
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 0 deletions.
70 changes: 70 additions & 0 deletions 1.21_linux/runtime/cgocall.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//--append

// This change is from https://go-review.googlesource.com/c/go/+/527715.

// Set or reset the system stack bounds for a callback on sp.
//
// Must be nosplit because it is called by needm prior to fully initializing
// the M.
//
//go:nosplit
func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) {
g0 := mp.g0
if sp > g0.stack.lo && sp <= g0.stack.hi {
// Stack already in bounds, nothing to do.
return
}

if mp.ncgo > 0 {
// ncgo > 0 indicates that this M was in Go further up the stack
// (it called C and is now receiving a callback). It is not
// safe for the C call to change the stack out from under us.

// Note that this case isn't possible for signal == true, as
// that is always passing a new M from needm.

// Stack is bogus, but reset the bounds anyway so we can print.
hi := g0.stack.hi
lo := g0.stack.lo
g0.stack.hi = sp + 1024
g0.stack.lo = sp - 32*1024
g0.stackguard0 = g0.stack.lo + stackGuard

print("M ", mp.id, " procid ", mp.procid, " runtime: cgocallback with sp=", hex(sp), " out of bounds [", hex(lo), ", ", hex(hi), "]")
print("\n")
exit(2)
}

// This M does not have Go further up the stack. However, it may have
// previously called into Go, initializing the stack bounds. Between
// that call returning and now the stack may have changed (perhaps the
// C thread is running a coroutine library). We need to update the
// stack bounds for this case.
//
// Set the stack bounds to match the current stack. If we don't
// actually know how big the stack is, like we don't know how big any
// scheduling stack is, but we assume there's at least 32 kB. If we
// can get a more accurate stack bound from pthread, use that, provided
// it actually contains SP..
g0.stack.hi = sp + 1024
g0.stack.lo = sp - 32*1024
if !signal && _cgo_getstackbound != nil {
// Don't adjust if called from the signal handler.
// We are on the signal stack, not the pthread stack.
// (We could get the stack bounds from sigaltstack, but
// we're getting out of the signal handler very soon
// anyway. Not worth it.)
var bounds [2]uintptr
asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds))
// getstackbound is an unsupported no-op on Windows.
//
// Don't use these bounds if they don't contain SP. Perhaps we
// were called by something not using the standard thread
// stack.
if bounds[0] != 0 && sp > bounds[0] && sp <= bounds[1] {
g0.stack.lo = bounds[0]
g0.stack.hi = bounds[1]
}
}
g0.stackguard0 = g0.stack.lo + stackGuard
}
51 changes: 51 additions & 0 deletions 1.21_linux/runtime/proc.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//--from
// Install g (= m->g0) and set the stack bounds
// to match the current stack. If we don't actually know
// how big the stack is, like we don't know how big any
// scheduling stack is, but we assume there's at least 32 kB.
// If we can get a more accurate stack bound from pthread,
// use that.
setg(mp.g0)
gp := getg()
gp.stack.hi = getcallersp() + 1024
gp.stack.lo = getcallersp() - 32*1024
if !signal && _cgo_getstackbound != nil {
// Don't adjust if called from the signal handler.
// We are on the signal stack, not the pthread stack.
// (We could get the stack bounds from sigaltstack, but
// we're getting out of the signal handler very soon
// anyway. Not worth it.)
var bounds [2]uintptr
asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds))
// getstackbound is an unsupported no-op on Windows.
if bounds[0] != 0 {
gp.stack.lo = bounds[0]
gp.stack.hi = bounds[1]
}
}
gp.stackguard0 = gp.stack.lo + stackGuard
//--to
// This change is from https://go-review.googlesource.com/c/go/+/527715.

// Install g (= m->g0) and set the stack bounds
// to match the current stack.
setg(mp.g0)
sp := getcallersp()
callbackUpdateSystemStack(mp, sp, signal)
//--from
// NOTE: this always runs without a P, so, nowritebarrierrec required.
//
//go:nowritebarrierrec
func dropm() {
//--to
// This change is from https://go-review.googlesource.com/c/go/+/527715.
//
// This always runs without a P, so //go:nowritebarrierrec is required.
//
// This may run with a different stack than was recorded in g0 (there is no
// call to callbackUpdateSystemStack prior to dropm), so this must be
// //go:nosplit to avoid the stack bounds check.
//
//go:nowritebarrierrec
//go:nosplit
func dropm() {

0 comments on commit 02e7122

Please sign in to comment.