mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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:
parent
91ca80f970
commit
5cd1b73772
3 changed files with 46 additions and 0 deletions
|
|
@ -1235,10 +1235,12 @@ func throw(s string) {
|
|||
//
|
||||
//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")
|
||||
|
|
@ -1248,6 +1250,27 @@ func fatal(s string) {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) {
|
|||
{"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 {
|
||||
|
|
|
|||
21
src/runtime/testdata/testprog/panicprint.go
vendored
21
src/runtime/testdata/testprog/panicprint.go
vendored
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
|
||||
type MyBool bool
|
||||
type MyComplex128 complex128
|
||||
type MyComplex64 complex64
|
||||
|
|
@ -90,6 +92,23 @@ func panicCustomFloat32() {
|
|||
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)
|
||||
|
|
@ -108,4 +127,6 @@ func init() {
|
|||
register("panicCustomUint32", panicCustomUint32)
|
||||
register("panicCustomUint64", panicCustomUint64)
|
||||
register("panicCustomUintptr", panicCustomUintptr)
|
||||
register("panicDeferFatal", panicDeferFatal)
|
||||
register("panicDoublieDeferFatal", panicDoublieDeferFatal)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue