aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/panic.go
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2025-02-18 17:34:24 -0500
committerDavid Chase <drchase@google.com>2025-02-19 08:27:06 -0800
commit9ddeac30b5c41f223564e1dedef3095a5a909cb9 (patch)
treef0db5d7e6aa50c7a00bd7a1f993bbab438def320 /src/runtime/panic.go
parent4267fd389e941cf197cc3890cc42e474866c0d30 (diff)
downloadgo-9ddeac30b5c41f223564e1dedef3095a5a909cb9.tar.xz
cmd/compile, runtime: use deferreturn as target PC for recover from deferrangefunc
The existing code for recover from deferrangefunc was broken in several ways. 1. the code following a deferrangefunc call did not check the return value for an out-of-band value indicating "return now" (i.e., recover was called) 2. the returned value was delivered using a bespoke ABI that happened to match on register-ABI platforms, but not on older stack-based ABI. 3. the returned value was the wrong width (1 word versus 2) and type/value(integer 1, not a pointer to anything) for deferrangefunc's any-typed return value (in practice, the OOB value check could catch this, but still, it's sketchy). This -- using the deferreturn lookup method already in place for open-coded defers -- turned out to be a much-less-ugly way of obtaining the desired transfer of control for recover(). TODO: we also could do this for regular defer, and delete some code. Fixes #71675 Change-Id: If7d7ea789ad4320821aab3b443759a7d71647ff0 Reviewed-on: https://go-review.googlesource.com/c/go/+/650476 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go9
1 files changed, 8 insertions, 1 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 2dd3c3c2db..1ed2503320 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -391,10 +391,15 @@ func deferrangefunc() any {
throw("defer on system stack")
}
+ fn := findfunc(sys.GetCallerPC())
+ if fn.deferreturn == 0 {
+ throw("no deferreturn")
+ }
+
d := newdefer()
d.link = gp._defer
gp._defer = d
- d.pc = sys.GetCallerPC()
+ d.pc = fn.entry() + uintptr(fn.deferreturn)
// We must not be preempted between calling GetCallerSP and
// storing it to d.sp because GetCallerSP's result is a
// uintptr stack pointer.
@@ -1258,6 +1263,8 @@ func recovery(gp *g) {
// only gets us to the caller's fp.
gp.sched.bp = sp - goarch.PtrSize
}
+ // The value in ret is delivered IN A REGISTER, even if there is a
+ // stack ABI.
gp.sched.ret = 1
gogo(&gp.sched)
}