// 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
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)
if gp.m.throwing == 0 {
gp.m.throwing = 1
}
- startpanic()
- dopanic(0)
+ fatalpanic(nil)
*(*int)(nil) = 0 // not reached
}
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")
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.
default:
// Can't even print! Just exit.
exit(5)
+ return false // Need to return something.
}
}