Skip to content

Commit 5cd1b73

Browse files
qiulaidongfenggopherbot
authored andcommitted
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>
1 parent 91ca80f commit 5cd1b73

File tree

3 files changed

+46
-0
lines changed

3 files changed

+46
-0
lines changed

src/runtime/panic.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,10 +1235,12 @@ func throw(s string) {
12351235
//
12361236
//go:nosplit
12371237
func fatal(s string) {
1238+
p := getg()._panic
12381239
// Everything fatal does should be recursively nosplit so it
12391240
// can be called even when it's unsafe to grow the stack.
12401241
printlock() // Prevent multiple interleaved fatal reports. See issue 69447.
12411242
systemstack(func() {
1243+
printPreFatalDeferPanic(p)
12421244
print("fatal error: ")
12431245
printindented(s) // logically printpanicval(s), but avoids convTstring write barrier
12441246
print("\n")
@@ -1248,6 +1250,27 @@ func fatal(s string) {
12481250
printunlock()
12491251
}
12501252

1253+
// printPreFatalDeferPanic prints the panic
1254+
// when fatal occurs in panics while running defer.
1255+
func printPreFatalDeferPanic(p *_panic) {
1256+
// Don`t call preprintpanics, because
1257+
// don't want to call String/Error on the panicked values.
1258+
// When we fatal we really want to just print and exit,
1259+
// no more executing user Go code.
1260+
for x := p; x != nil; x = x.link {
1261+
if x.link != nil && *efaceOf(&x.link.arg) == *efaceOf(&x.arg) {
1262+
// This panic contains the same value as the next one in the chain.
1263+
// Mark it as repanicked. We will skip printing it twice in a row.
1264+
x.link.repanicked = true
1265+
}
1266+
}
1267+
if p != nil {
1268+
printpanics(p)
1269+
// make fatal have the same indentation as non-first panics.
1270+
print("\t")
1271+
}
1272+
}
1273+
12511274
// runningPanicDefers is non-zero while running deferred functions for panic.
12521275
// This is used to try hard to get a panic stack trace out when exiting.
12531276
var runningPanicDefers atomic.Uint32

src/runtime/panic_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) {
3434
{"panicCustomUint32", `panic: main.MyUint32(93)`},
3535
{"panicCustomUint64", `panic: main.MyUint64(93)`},
3636
{"panicCustomUintptr", `panic: main.MyUintptr(93)`},
37+
{"panicDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\")\n\tfatal error: sync: unlock of unlocked mutex"},
38+
{"panicDoublieDeferFatal", "panic: runtime.errorString(\"invalid memory address or nil pointer dereference\") [recovered, repanicked]\n\tfatal error: sync: unlock of unlocked mutex"},
3739
}
3840

3941
for _, tt := range tests {

src/runtime/testdata/testprog/panicprint.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package main
66

7+
import "sync"
8+
79
type MyBool bool
810
type MyComplex128 complex128
911
type MyComplex64 complex64
@@ -90,6 +92,23 @@ func panicCustomFloat32() {
9092
panic(MyFloat32(-93.70))
9193
}
9294

95+
func panicDeferFatal() {
96+
var mu sync.Mutex
97+
defer mu.Unlock()
98+
var i *int
99+
*i = 0
100+
}
101+
102+
func panicDoublieDeferFatal() {
103+
var mu sync.Mutex
104+
defer mu.Unlock()
105+
defer func() {
106+
panic(recover())
107+
}()
108+
var i *int
109+
*i = 0
110+
}
111+
93112
func init() {
94113
register("panicCustomComplex64", panicCustomComplex64)
95114
register("panicCustomComplex128", panicCustomComplex128)
@@ -108,4 +127,6 @@ func init() {
108127
register("panicCustomUint32", panicCustomUint32)
109128
register("panicCustomUint64", panicCustomUint64)
110129
register("panicCustomUintptr", panicCustomUintptr)
130+
register("panicDeferFatal", panicDeferFatal)
131+
register("panicDoublieDeferFatal", panicDoublieDeferFatal)
111132
}

0 commit comments

Comments
 (0)