//
//go:nosplit
func fatal(s string) {
+ p := getg()._panic
// Everything fatal does should be recursively nosplit so it
// can be called even when it's unsafe to grow the stack.
printlock() // Prevent multiple interleaved fatal reports. See issue 69447.
systemstack(func() {
+ printPreFatalDeferPanic(p)
print("fatal error: ")
printindented(s) // logically printpanicval(s), but avoids convTstring write barrier
print("\n")
printunlock()
}
+// printPreFatalDeferPanic prints the panic
+// when fatal occurs in panics while running defer.
+func printPreFatalDeferPanic(p *_panic) {
+ // Don`t call preprintpanics, because
+ // don't want to call String/Error on the panicked values.
+ // When we fatal we really want to just print and exit,
+ // no more executing user Go code.
+ for x := p; x != nil; x = x.link {
+ if x.link != nil && *efaceOf(&x.link.arg) == *efaceOf(&x.arg) {
+ // This panic contains the same value as the next one in the chain.
+ // Mark it as repanicked. We will skip printing it twice in a row.
+ x.link.repanicked = true
+ }
+ }
+ if p != nil {
+ printpanics(p)
+ // make fatal have the same indentation as non-first panics.
+ print("\t")
+ }
+}
+
// runningPanicDefers is non-zero while running deferred functions for panic.
// This is used to try hard to get a panic stack trace out when exiting.
var runningPanicDefers atomic.Uint32
{"panicCustomUint32", `panic: main.MyUint32(93)`},
{"panicCustomUint64", `panic: main.MyUint64(93)`},
{"panicCustomUintptr", `panic: main.MyUintptr(93)`},
+ {"panicDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\")\n\tfatal error: sync: unlock of unlocked mutex"},
+ {"panicDoublieDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\") [recovered, repanicked]\n\tfatal error: sync: unlock of unlocked mutex"},
}
for _, tt := range tests {
package main
+import "sync"
+
type MyBool bool
type MyComplex128 complex128
type MyComplex64 complex64
panic(MyFloat32(-93.70))
}
+func panicDeferFatal() {
+ var mu sync.Mutex
+ defer mu.Unlock()
+ var i *int
+ *i = 0
+}
+
+func panicDoublieDeferFatal() {
+ var mu sync.Mutex
+ defer mu.Unlock()
+ defer func() {
+ panic(recover())
+ }()
+ var i *int
+ *i = 0
+}
+
func init() {
register("panicCustomComplex64", panicCustomComplex64)
register("panicCustomComplex128", panicCustomComplex128)
register("panicCustomUint32", panicCustomUint32)
register("panicCustomUint64", panicCustomUint64)
register("panicCustomUintptr", panicCustomUintptr)
+ register("panicDeferFatal", panicDeferFatal)
+ register("panicDoublieDeferFatal", panicDoublieDeferFatal)
}