-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1.21_linux/runtime: bug fix: crash with 'morestack on g0'
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
1 parent
eeb89f1
commit 02e7122
Showing
2 changed files
with
121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() { |