]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: don't discard value from panic while panicking
authorhopehook <hopehook.com@gmail.com>
Tue, 12 Apr 2022 09:46:36 +0000 (17:46 +0800)
committerGopher Robot <gobot@golang.org>
Fri, 15 Apr 2022 01:08:38 +0000 (01:08 +0000)
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 <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/runtime/crash_test.go
src/runtime/panic.go
src/runtime/testdata/testprog/crash.go

index d8cabcdda28080b09f4f80ae47ed2ec3138eb6e3..01d7cbeb2904b9ebcfda36978cf3b71bd883d8dc 100644 (file)
@@ -800,3 +800,47 @@ func TestDoublePanic(t *testing.T) {
                }
        }
 }
+
+// Test that panic while panicking discards error message
+// See issue 52257
+func TestPanicWhilePanicking(t *testing.T) {
+       tests := []struct {
+               Want string
+               Func string
+       }{
+               {
+                       "panic while printing panic value: important error message",
+                       "ErrorPanic",
+               },
+               {
+                       "panic while printing panic value: important stringer message",
+                       "StringerPanic",
+               },
+               {
+                       "panic while printing panic value: type",
+                       "DoubleErrorPanic",
+               },
+               {
+                       "panic while printing panic value: type",
+                       "DoubleStringerPanic",
+               },
+               {
+                       "panic while printing panic value: type",
+                       "CircularPanic",
+               },
+               {
+                       "important string message",
+                       "StringPanic",
+               },
+               {
+                       "nil",
+                       "NilPanic",
+               },
+       }
+       for _, x := range tests {
+               output := runTestProg(t, "testprog", x.Func)
+               if !strings.Contains(output, x.Want) {
+                       t.Errorf("output does not contain %q:\n%s", x.Want, output)
+               }
+       }
+}
index f2137c6853bb90b3620ef1313c7bb704ce31f944..e4cc7bfb315d040af137737564fb429d1fe2ab9b 100644 (file)
@@ -525,8 +525,14 @@ func Goexit() {
 // Used when crashing with panicking.
 func preprintpanics(p *_panic) {
        defer func() {
-               if recover() != nil {
-                       throw("panic while printing panic value")
+               text := "panic while printing panic value"
+               switch r := recover().(type) {
+               case nil:
+                       // nothing to do
+               case string:
+                       throw(text + ": " + r)
+               default:
+                       throw(text + ": type " + efaceOf(&r)._type.string())
                }
        }()
        for p != nil {
index c4990cdda9a078c1829a8282aab72ca309def9cf..a2294ba14950a4b516c106942303d71f7574d66a 100644 (file)
@@ -12,6 +12,13 @@ import (
 func init() {
        register("Crash", Crash)
        register("DoublePanic", DoublePanic)
+       register("ErrorPanic", ErrorPanic)
+       register("StringerPanic", StringerPanic)
+       register("DoubleErrorPanic", DoubleErrorPanic)
+       register("DoubleStringerPanic", DoubleStringerPanic)
+       register("StringPanic", StringPanic)
+       register("NilPanic", NilPanic)
+       register("CircularPanic", CircularPanic)
 }
 
 func test(name string) {
@@ -64,3 +71,69 @@ func DoublePanic() {
        }()
        panic(P("XXX"))
 }
+
+// Test that panic while panicking discards error message
+// See issue 52257
+type exampleError struct{}
+
+func (e exampleError) Error() string {
+       panic("important error message")
+}
+
+func ErrorPanic() {
+       panic(exampleError{})
+}
+
+type examplePanicError struct{}
+
+func (e examplePanicError) Error() string {
+       panic(exampleError{})
+}
+
+func DoubleErrorPanic() {
+       panic(examplePanicError{})
+}
+
+type exampleStringer struct{}
+
+func (s exampleStringer) String() string {
+       panic("important stringer message")
+}
+
+func StringerPanic() {
+       panic(exampleStringer{})
+}
+
+type examplePanicStringer struct{}
+
+func (s examplePanicStringer) String() string {
+       panic(exampleStringer{})
+}
+
+func DoubleStringerPanic() {
+       panic(examplePanicStringer{})
+}
+
+func StringPanic() {
+       panic("important string message")
+}
+
+func NilPanic() {
+       panic(nil)
+}
+
+type exampleCircleStartError struct {}
+
+func (e exampleCircleStartError) Error() string {
+       panic(exampleCircleEndError{})
+}
+
+type exampleCircleEndError struct {}
+
+func (e exampleCircleEndError) Error() string {
+       panic(exampleCircleStartError{})
+}
+
+func CircularPanic() {
+       panic(exampleCircleStartError{})
+}
\ No newline at end of file