diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index 0b313d75e3..b05965b63d 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -121,7 +121,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { Throw: _g_.m.throwing = 1 _g_.m.caughtsig.set(gp) - startpanic() + startpanic_m() print(notestr, "\n") print("PC=", hex(c.pc()), "\n") print("\n") diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 715e802d10..cd2b18cc51 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -542,15 +542,9 @@ func gopanic(e interface{}) { // the world, we call preprintpanics to invoke all necessary Error // and String methods to prepare the panic strings before startpanic. preprintpanics(gp._panic) - startpanic() - // startpanic set panicking, which will block main from exiting, - // so now OK to decrement runningPanicDefers. - atomic.Xadd(&runningPanicDefers, -1) - - printpanics(gp._panic) - dopanic(0) // should not return - *(*int)(nil) = 0 // not reached + fatalpanic(gp._panic) // should not return + *(*int)(nil) = 0 // not reached } // getargp returns the location where the caller @@ -585,22 +579,6 @@ func gorecover(argp uintptr) interface{} { return nil } -//go:nosplit -func startpanic() { - systemstack(startpanic_m) -} - -//go:nosplit -func dopanic(unused int) { - pc := getcallerpc() - sp := getcallersp(unsafe.Pointer(&unused)) - gp := getg() - systemstack(func() { - dopanic_m(gp, pc, sp) // should never return - }) - *(*int)(nil) = 0 -} - //go:linkname sync_throw sync.throw func sync_throw(s string) { throw(s) @@ -613,8 +591,7 @@ func throw(s string) { if gp.m.throwing == 0 { gp.m.throwing = 1 } - startpanic() - dopanic(0) + fatalpanic(nil) *(*int)(nil) = 0 // not reached } @@ -655,13 +632,48 @@ func recovery(gp *g) { gogo(&gp.sched) } +// fatalpanic implements an unrecoverable panic. It freezes the +// system, prints panic messages if msgs != nil, prints stack traces +// starting from its caller, and terminates the process. +// +// If msgs != nil, it also decrements runningPanicDefers once main is +// blocked from exiting. +// +//go:nosplit +func fatalpanic(msgs *_panic) { + pc := getcallerpc() + sp := getcallersp(unsafe.Pointer(&msgs)) + gp := getg() + // Switch to the system stack to avoid any stack growth, which + // may make things worse if the runtime is in a bad state. + systemstack(func() { + if startpanic_m() && msgs != nil { + // There were panic messages and startpanic_m + // says it's okay to try to print them. + + // startpanic_m set panicking, which will + // block main from exiting, so now OK to + // decrement runningPanicDefers. + atomic.Xadd(&runningPanicDefers, -1) + + printpanics(msgs) + } + + dopanic_m(gp, pc, sp) // should never return + }) + *(*int)(nil) = 0 // not reached +} + // startpanic_m prepares for an unrecoverable panic. // +// It returns true if panic messages should be printed, or false if +// the runtime is in bad shape and should just print stacks. +// // It can have write barriers because the write barrier explicitly // ignores writes once dying > 0. // //go:yeswritebarrierrec -func startpanic_m() { +func startpanic_m() bool { _g_ := getg() if mheap_.cachealloc.size == 0 { // very early print("runtime: panic before malloc heap initialized\n") @@ -682,15 +694,13 @@ func startpanic_m() { schedtrace(true) } freezetheworld() - return + return true case 1: - // Something failed while panicking, probably the print of the - // argument to panic(). Just print a stack trace and exit. + // Something failed while panicking. + // Just print a stack trace and exit. _g_.m.dying = 2 print("panic during panic\n") - dopanic(0) - exit(3) - fallthrough + return false case 2: // This is a genuine bug in the runtime, we couldn't even // print the stack trace successfully. @@ -701,6 +711,7 @@ func startpanic_m() { default: // Can't even print! Just exit. exit(5) + return false // Need to return something. } } diff --git a/src/runtime/signal_sighandler.go b/src/runtime/signal_sighandler.go index bf2237c981..13448929bc 100644 --- a/src/runtime/signal_sighandler.go +++ b/src/runtime/signal_sighandler.go @@ -83,7 +83,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { _g_.m.caughtsig.set(gp) if crashing == 0 { - startpanic() + startpanic_m() } if sig < uint32(len(sigtable)) {