diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 1e61c90aefe..bf79b6518e8 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -1142,18 +1142,21 @@ func gorecover(_ uintptr) any { nonWrapperFrames := 0 loop: for ; u.valid(); u.next() { - switch u.frame.fn.funcID { - case abi.FuncIDWrapper: - continue - case abi.FuncID_gopanic: - if u.frame.fp == uintptr(p.gopanicFP) && nonWrapperFrames > 0 { - canRecover = true - } - break loop - default: - nonWrapperFrames++ - if nonWrapperFrames > 1 { + for iu, f := newInlineUnwinder(u.frame.fn, u.symPC()); f.valid(); f = iu.next(f) { + sf := iu.srcFunc(f) + switch sf.funcID { + case abi.FuncIDWrapper: + continue + case abi.FuncID_gopanic: + if u.frame.fp == uintptr(p.gopanicFP) && nonWrapperFrames > 0 { + canRecover = true + } break loop + default: + nonWrapperFrames++ + if nonWrapperFrames > 1 { + break loop + } } } } diff --git a/test/fixedbugs/issue73916.go b/test/fixedbugs/issue73916.go new file mode 100644 index 00000000000..6060c3f235a --- /dev/null +++ b/test/fixedbugs/issue73916.go @@ -0,0 +1,32 @@ +// run + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func callRecover() { + if recover() != nil { + println("recovered") + } +} + +func F(int) { callRecover() } + +func main() { + mustPanic(func() { + defer F(1) + panic("XXX") + }) +} + +func mustPanic(f func()) { + defer func() { + r := recover() + if r == nil { + panic("didn't panic") + } + }() + f() +} diff --git a/test/fixedbugs/issue73916b.go b/test/fixedbugs/issue73916b.go new file mode 100644 index 00000000000..29393fa502a --- /dev/null +++ b/test/fixedbugs/issue73916b.go @@ -0,0 +1,34 @@ +// run + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func callRecover() { + func() { + if recover() != nil { + println("recovered") + } + }() +} + +func F() int { callRecover(); return 0 } + +func main() { + mustPanic(func() { + defer F() + panic("XXX") + }) +} + +func mustPanic(f func()) { + defer func() { + r := recover() + if r == nil { + panic("didn't panic") + } + }() + f() +} diff --git a/test/fixedbugs/issue73917.go b/test/fixedbugs/issue73917.go new file mode 100644 index 00000000000..9c0330d19a3 --- /dev/null +++ b/test/fixedbugs/issue73917.go @@ -0,0 +1,40 @@ +// run + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func callRecover() { + if recover() != nil { + println("recovered") + } +} + +type T int + +func (*T) M() { callRecover() } + +type S struct{ *T } // has a wrapper S.M wrapping (*T.M) + +var p = S{new(T)} + +var fn = S.M // using a function pointer to force using the wrapper + +func main() { + mustPanic(func() { + defer fn(p) + panic("XXX") + }) +} + +func mustPanic(f func()) { + defer func() { + r := recover() + if r == nil { + panic("didn't panic") + } + }() + f() +} diff --git a/test/fixedbugs/issue73920.go b/test/fixedbugs/issue73920.go new file mode 100644 index 00000000000..f0a711b0451 --- /dev/null +++ b/test/fixedbugs/issue73920.go @@ -0,0 +1,40 @@ +// run + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func callRecover() { + if recover() != nil { + println("recovered") + } +} + +type T int + +func (*T) M() { callRecover() } + +type S struct{ *T } // has a wrapper (*S).M wrapping (*T.M) + +var p = &S{new(T)} + +var fn = (*S).M // using a function pointer to force using the wrapper + +func main() { + mustPanic(func() { + defer fn(p) + panic("XXX") + }) +} + +func mustPanic(f func()) { + defer func() { + r := recover() + if r == nil { + panic("didn't panic") + } + }() + f() +}