Skip to content

Commit 5a4f0b6

Browse files
hopehookgopherbot
authored andcommitted
runtime: don't discard value from panic while panicking
In issue #17671, there are a endless loop if printing the panic value panics, CL 30358 has fixed that. As issue #52257 pointed out, above change should not discard the value from panic while panicking. With this CL, when we recover from a panic in error.Error() or stringer.String(), and the recovered value is string, then we can print it normally. Fixes #52257 Change-Id: Icfcc4a1a390635de405eea04904b4607ae9e3055 Reviewed-on: https://go-review.googlesource.com/c/go/+/399874 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 78bea70 commit 5a4f0b6

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

src/runtime/crash_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,3 +800,47 @@ func TestDoublePanic(t *testing.T) {
800800
}
801801
}
802802
}
803+
804+
// Test that panic while panicking discards error message
805+
// See issue 52257
806+
func TestPanicWhilePanicking(t *testing.T) {
807+
tests := []struct {
808+
Want string
809+
Func string
810+
}{
811+
{
812+
"panic while printing panic value: important error message",
813+
"ErrorPanic",
814+
},
815+
{
816+
"panic while printing panic value: important stringer message",
817+
"StringerPanic",
818+
},
819+
{
820+
"panic while printing panic value: type",
821+
"DoubleErrorPanic",
822+
},
823+
{
824+
"panic while printing panic value: type",
825+
"DoubleStringerPanic",
826+
},
827+
{
828+
"panic while printing panic value: type",
829+
"CircularPanic",
830+
},
831+
{
832+
"important string message",
833+
"StringPanic",
834+
},
835+
{
836+
"nil",
837+
"NilPanic",
838+
},
839+
}
840+
for _, x := range tests {
841+
output := runTestProg(t, "testprog", x.Func)
842+
if !strings.Contains(output, x.Want) {
843+
t.Errorf("output does not contain %q:\n%s", x.Want, output)
844+
}
845+
}
846+
}

src/runtime/panic.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,14 @@ func Goexit() {
525525
// Used when crashing with panicking.
526526
func preprintpanics(p *_panic) {
527527
defer func() {
528-
if recover() != nil {
529-
throw("panic while printing panic value")
528+
text := "panic while printing panic value"
529+
switch r := recover().(type) {
530+
case nil:
531+
// nothing to do
532+
case string:
533+
throw(text + ": " + r)
534+
default:
535+
throw(text + ": type " + efaceOf(&r)._type.string())
530536
}
531537
}()
532538
for p != nil {

src/runtime/testdata/testprog/crash.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ import (
1212
func init() {
1313
register("Crash", Crash)
1414
register("DoublePanic", DoublePanic)
15+
register("ErrorPanic", ErrorPanic)
16+
register("StringerPanic", StringerPanic)
17+
register("DoubleErrorPanic", DoubleErrorPanic)
18+
register("DoubleStringerPanic", DoubleStringerPanic)
19+
register("StringPanic", StringPanic)
20+
register("NilPanic", NilPanic)
21+
register("CircularPanic", CircularPanic)
1522
}
1623

1724
func test(name string) {
@@ -64,3 +71,69 @@ func DoublePanic() {
6471
}()
6572
panic(P("XXX"))
6673
}
74+
75+
// Test that panic while panicking discards error message
76+
// See issue 52257
77+
type exampleError struct{}
78+
79+
func (e exampleError) Error() string {
80+
panic("important error message")
81+
}
82+
83+
func ErrorPanic() {
84+
panic(exampleError{})
85+
}
86+
87+
type examplePanicError struct{}
88+
89+
func (e examplePanicError) Error() string {
90+
panic(exampleError{})
91+
}
92+
93+
func DoubleErrorPanic() {
94+
panic(examplePanicError{})
95+
}
96+
97+
type exampleStringer struct{}
98+
99+
func (s exampleStringer) String() string {
100+
panic("important stringer message")
101+
}
102+
103+
func StringerPanic() {
104+
panic(exampleStringer{})
105+
}
106+
107+
type examplePanicStringer struct{}
108+
109+
func (s examplePanicStringer) String() string {
110+
panic(exampleStringer{})
111+
}
112+
113+
func DoubleStringerPanic() {
114+
panic(examplePanicStringer{})
115+
}
116+
117+
func StringPanic() {
118+
panic("important string message")
119+
}
120+
121+
func NilPanic() {
122+
panic(nil)
123+
}
124+
125+
type exampleCircleStartError struct {}
126+
127+
func (e exampleCircleStartError) Error() string {
128+
panic(exampleCircleEndError{})
129+
}
130+
131+
type exampleCircleEndError struct {}
132+
133+
func (e exampleCircleEndError) Error() string {
134+
panic(exampleCircleStartError{})
135+
}
136+
137+
func CircularPanic() {
138+
panic(exampleCircleStartError{})
139+
}

0 commit comments

Comments
 (0)