break
}
}
+ if flags&_SigPanic != 0 && gp.throwsplit {
+ // We can't safely sigpanic because it may grow the
+ // stack. Abort in the signal handler instead.
+ flags = (flags &^ _SigPanic) | _SigThrow
+ }
if flags&_SigGoExit != 0 {
exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
}
exit(2)
}
+// canpanic returns false if a signal should throw instead of
+// panicking.
+//
//go:nosplit
func canpanic(gp *g) bool {
// Note that g is m->gsignal, different from gp.
if sig < uint32(len(sigtable)) {
flags = sigtable[sig].flags
}
+ if flags&_SigPanic != 0 && gp.throwsplit {
+ // We can't safely sigpanic because it may grow the
+ // stack. Abort in the signal handler instead.
+ flags = (flags &^ _SigPanic) | _SigThrow
+ }
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
// The signal is going to cause a panic.
// Arrange the stack so that it looks like the point
// the signal handler. The effect is that the program will act as
// though the function that got the signal simply called sigpanic
// instead.
+//
+// This must NOT be nosplit because the linker doesn't know where
+// sigpanic calls can be injected.
+//
+// The signal handler must not inject a call to sigpanic if
+// getg().throwsplit, since sigpanic may need to grow the stack.
func sigpanic() {
g := getg()
if !canpanic(g) {
return _EXCEPTION_CONTINUE_SEARCH
}
+ if gp.throwsplit {
+ // We can't safely sigpanic because it may grow the
+ // stack. Let it fall through.
+ return _EXCEPTION_CONTINUE_SEARCH
+ }
+
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break