runtime: correctly print panics before fatal-ing on defer

Fixes #67792

Change-Id: I93d16580cb31e54cee7c8490212404e4d0dec446
Reviewed-on: https://go-review.googlesource.com/c/go/+/613757
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
qiulaidongfeng 2024-09-17 20:10:20 +08:00 committed by Gopher Robot
parent 91ca80f970
commit 5cd1b73772
3 changed files with 46 additions and 0 deletions

View file

@ -1235,10 +1235,12 @@ func throw(s string) {
// //
//go:nosplit //go:nosplit
func fatal(s string) { func fatal(s string) {
p := getg()._panic
// Everything fatal does should be recursively nosplit so it // Everything fatal does should be recursively nosplit so it
// can be called even when it's unsafe to grow the stack. // can be called even when it's unsafe to grow the stack.
printlock() // Prevent multiple interleaved fatal reports. See issue 69447. printlock() // Prevent multiple interleaved fatal reports. See issue 69447.
systemstack(func() { systemstack(func() {
printPreFatalDeferPanic(p)
print("fatal error: ") print("fatal error: ")
printindented(s) // logically printpanicval(s), but avoids convTstring write barrier printindented(s) // logically printpanicval(s), but avoids convTstring write barrier
print("\n") print("\n")
@ -1248,6 +1250,27 @@ func fatal(s string) {
printunlock() 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. // 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. // This is used to try hard to get a panic stack trace out when exiting.
var runningPanicDefers atomic.Uint32 var runningPanicDefers atomic.Uint32

View file

@ -34,6 +34,8 @@ func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) {
{"panicCustomUint32", `panic: main.MyUint32(93)`}, {"panicCustomUint32", `panic: main.MyUint32(93)`},
{"panicCustomUint64", `panic: main.MyUint64(93)`}, {"panicCustomUint64", `panic: main.MyUint64(93)`},
{"panicCustomUintptr", `panic: main.MyUintptr(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 { for _, tt := range tests {

View file

@ -4,6 +4,8 @@
package main package main
import "sync"
type MyBool bool type MyBool bool
type MyComplex128 complex128 type MyComplex128 complex128
type MyComplex64 complex64 type MyComplex64 complex64
@ -90,6 +92,23 @@ func panicCustomFloat32() {
panic(MyFloat32(-93.70)) 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() { func init() {
register("panicCustomComplex64", panicCustomComplex64) register("panicCustomComplex64", panicCustomComplex64)
register("panicCustomComplex128", panicCustomComplex128) register("panicCustomComplex128", panicCustomComplex128)
@ -108,4 +127,6 @@ func init() {
register("panicCustomUint32", panicCustomUint32) register("panicCustomUint32", panicCustomUint32)
register("panicCustomUint64", panicCustomUint64) register("panicCustomUint64", panicCustomUint64)
register("panicCustomUintptr", panicCustomUintptr) register("panicCustomUintptr", panicCustomUintptr)
register("panicDeferFatal", panicDeferFatal)
register("panicDoublieDeferFatal", panicDoublieDeferFatal)
} }