Skip to content

Commit 9483a0b

Browse files
committed
runtime: don't grow the stack on sigpanic if throwsplit
Currently, if a _SigPanic signal arrives in a throwsplit context, nothing is stopping the runtime from injecting a call to sigpanic that may attempt to grow the stack. This will fail and, in turn, mask the real problem. Fix this by checking for throwsplit in the signal handler itself before injecting the sigpanic call. Updates #21431, where this problem is likely masking the real problem. Change-Id: I64b61ff08e8c4d6f6c0fb01315d7d5e66bf1d3e2 Reviewed-on: https://go-review.googlesource.com/87595 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 9b49ac0 commit 9483a0b

File tree

5 files changed

+25
-0
lines changed

5 files changed

+25
-0
lines changed

src/runtime/os3_plan9.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
4545
break
4646
}
4747
}
48+
if flags&_SigPanic != 0 && gp.throwsplit {
49+
// We can't safely sigpanic because it may grow the
50+
// stack. Abort in the signal handler instead.
51+
flags = (flags &^ _SigPanic) | _SigThrow
52+
}
4853
if flags&_SigGoExit != 0 {
4954
exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
5055
}

src/runtime/panic.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,9 @@ func dopanic_m(gp *g, pc, sp uintptr) {
752752
exit(2)
753753
}
754754

755+
// canpanic returns false if a signal should throw instead of
756+
// panicking.
757+
//
755758
//go:nosplit
756759
func canpanic(gp *g) bool {
757760
// Note that g is m->gsignal, different from gp.

src/runtime/signal_sighandler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
3838
if sig < uint32(len(sigtable)) {
3939
flags = sigtable[sig].flags
4040
}
41+
if flags&_SigPanic != 0 && gp.throwsplit {
42+
// We can't safely sigpanic because it may grow the
43+
// stack. Abort in the signal handler instead.
44+
flags = (flags &^ _SigPanic) | _SigThrow
45+
}
4146
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
4247
// The signal is going to cause a panic.
4348
// Arrange the stack so that it looks like the point

src/runtime/signal_unix.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,12 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
360360
// the signal handler. The effect is that the program will act as
361361
// though the function that got the signal simply called sigpanic
362362
// instead.
363+
//
364+
// This must NOT be nosplit because the linker doesn't know where
365+
// sigpanic calls can be injected.
366+
//
367+
// The signal handler must not inject a call to sigpanic if
368+
// getg().throwsplit, since sigpanic may need to grow the stack.
363369
func sigpanic() {
364370
g := getg()
365371
if !canpanic(g) {

src/runtime/signal_windows.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
7171
return _EXCEPTION_CONTINUE_SEARCH
7272
}
7373

74+
if gp.throwsplit {
75+
// We can't safely sigpanic because it may grow the
76+
// stack. Let it fall through.
77+
return _EXCEPTION_CONTINUE_SEARCH
78+
}
79+
7480
// Make it look like a call to the signal func.
7581
// Have to pass arguments out of band since
7682
// augmenting the stack frame would break

0 commit comments

Comments
 (0)