mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: iterate through inlinings when processing recover()
We care about the wrapper-ness of logical frames, not physical frames. Fixes #73916 Fixes #73917 Fixex #73920 Change-Id: Ia17c8390e71e6c0e13e23dcbb7bc7273ef25da90 Reviewed-on: https://go-review.googlesource.com/c/go/+/685375 Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
c76c3abc54
commit
08376e1a9c
5 changed files with 160 additions and 11 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
32
test/fixedbugs/issue73916.go
Normal file
32
test/fixedbugs/issue73916.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
34
test/fixedbugs/issue73916b.go
Normal file
34
test/fixedbugs/issue73916b.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
40
test/fixedbugs/issue73917.go
Normal file
40
test/fixedbugs/issue73917.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
40
test/fixedbugs/issue73920.go
Normal file
40
test/fixedbugs/issue73920.go
Normal file
|
|
@ -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()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue