diff options
| author | Keith Randall <khr@golang.org> | 2026-01-12 15:05:24 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-06 10:08:12 -0800 |
| commit | 50d988e4e037d9d41ac223a62706dfea47a100e4 (patch) | |
| tree | cccebaec15e091c18a1da50a0c0253c9809642be /src/runtime/panic_test.go | |
| parent | bf84b002d64d0b150818268e520fee0172a5c462 (diff) | |
| download | go-50d988e4e037d9d41ac223a62706dfea47a100e4.tar.xz | |
runtime: when panicking, skip ahead to previous panic
While looking up the stack for a defer to run, if we come across
a panic frame we can skip ahead (up) to where the previous panic
was looking for a defer to run.
Switch from keeping LR (the caller's pc) to PC (the frame's PC).
Seems easier to reason about.
Fixes #77062
Change-Id: Idb39411ebad8c072c8f65c62a518da848bddbd61
Reviewed-on: https://go-review.googlesource.com/c/go/+/738041
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/runtime/panic_test.go')
| -rw-r--r-- | src/runtime/panic_test.go | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/runtime/panic_test.go b/src/runtime/panic_test.go index 2b06bce45d..5a4b6ae633 100644 --- a/src/runtime/panic_test.go +++ b/src/runtime/panic_test.go @@ -5,8 +5,10 @@ package runtime_test import ( + "slices" "strings" "testing" + "time" ) // Test that panics print out the underlying value @@ -48,3 +50,51 @@ func TestPanicWithDirectlyPrintableCustomTypes(t *testing.T) { }) } } + +func TestPanicRecoverSpeed(t *testing.T) { + // For issue 77062. + t.Skip("This test is too flaky at the moment. But it does normally pass. Suggestions for making it less flaky are welcome.") + + // Recursive function that does defer/recover/repanic. + var f func(int) + f = func(n int) { + if n == 0 { + panic("done") + } + defer func() { + err := recover() + panic(err) + }() + f(n - 1) + } + + time := func(f func()) time.Duration { + var times []time.Duration + for range 10 { + start := time.Now() + f() + times = append(times, time.Since(start)) + } + slices.Sort(times) + times = times[1 : len(times)-1] // skip high and low, to reduce noise + var avg time.Duration + for _, v := range times { + avg += v / time.Duration(len(times)) + } + return avg + } + + a := time(func() { + defer func() { recover() }() + f(1024) + }) + b := time(func() { + defer func() { recover() }() + f(2048) + }) + m := b.Seconds() / a.Seconds() + t.Logf("a: %v, b: %v, m: %v", a, b, m) + if m > 3.5 { + t.Errorf("more than 2x time increase: %v", m) + } +} |
