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
|
//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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
21
src/runtime/testdata/testprog/panicprint.go
vendored
21
src/runtime/testdata/testprog/panicprint.go
vendored
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue