aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/panic.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/panic.go')
-rw-r--r--libgo/go/runtime/panic.go65
1 files changed, 32 insertions, 33 deletions
diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go
index a4b9a83..49c5f5e 100644
--- a/libgo/go/runtime/panic.go
+++ b/libgo/go/runtime/panic.go
@@ -281,29 +281,29 @@ func deferprocStack(d *_defer, frame *bool, pfn uintptr, arg unsafe.Pointer) {
// Each defer must be released with freedefer.
func newdefer() *_defer {
var d *_defer
- gp := getg()
- pp := gp.m.p.ptr()
+ mp := acquirem()
+ pp := mp.p.ptr()
if len(pp.deferpool) == 0 && sched.deferpool != nil {
- systemstack(func() {
- lock(&sched.deferlock)
- for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil {
- d := sched.deferpool
- sched.deferpool = d.link
- d.link = nil
- pp.deferpool = append(pp.deferpool, d)
- }
- unlock(&sched.deferlock)
- })
+ lock(&sched.deferlock)
+ for len(pp.deferpool) < cap(pp.deferpool)/2 && sched.deferpool != nil {
+ d := sched.deferpool
+ sched.deferpool = d.link
+ d.link = nil
+ pp.deferpool = append(pp.deferpool, d)
+ }
+ unlock(&sched.deferlock)
}
if n := len(pp.deferpool); n > 0 {
d = pp.deferpool[n-1]
pp.deferpool[n-1] = nil
pp.deferpool = pp.deferpool[:n-1]
}
+ releasem(mp)
+ mp, pp = nil, nil
+
if d == nil {
- systemstack(func() {
- d = new(_defer)
- })
+ // Allocate new defer.
+ d = new(_defer)
}
d.heap = true
return d
@@ -312,11 +312,16 @@ func newdefer() *_defer {
// Free the given defer.
// The defer cannot be used after this call.
//
-// This must not grow the stack because there may be a frame without a
-// stack map when this is called.
+// This is nosplit because the incoming defer is in a perilous state.
+// It's not on any defer list, so stack copying won't adjust stack
+// pointers in it (namely, d.link). Hence, if we were to copy the
+// stack, d could then contain a stale pointer.
//
//go:nosplit
func freedefer(d *_defer) {
+ d.link = nil
+ // After this point we can copy the stack.
+
if d._panic != nil {
freedeferpanic()
}
@@ -326,7 +331,8 @@ func freedefer(d *_defer) {
if !d.heap {
return
}
- pp := getg().m.p.ptr()
+ mp := acquirem()
+ pp := mp.p.ptr()
if len(pp.deferpool) == cap(pp.deferpool) {
// Transfer half of local cache to the central cache.
//
@@ -353,19 +359,12 @@ func freedefer(d *_defer) {
})
}
- // These lines used to be simply `*d = _defer{}` but that
- // started causing a nosplit stack overflow via typedmemmove.
- d.link = nil
- d.frame = nil
- d.panicStack = nil
- d.arg = nil
- d.retaddr = 0
- d.makefunccanrecover = false
- // d._panic and d.pfn must be nil already.
- // If not, we would have called freedeferpanic or freedeferfn above,
- // both of which throw.
+ *d = _defer{}
pp.deferpool = append(pp.deferpool, d)
+
+ releasem(mp)
+ mp, pp = nil, nil
}
// Separate function so that it can split stack.
@@ -636,7 +635,7 @@ func printpanics(p *_panic) {
}
// The implementation of the predeclared function panic.
-func gopanic(e interface{}) {
+func gopanic(e any) {
gp := getg()
if gp.m.curg != gp {
print("panic: ")
@@ -1237,15 +1236,15 @@ func canpanic(gp *g) bool {
// Note also that g->m can change at preemption, so m can go stale
// if this function ever makes a function call.
_g_ := getg()
- _m_ := _g_.m
+ mp := _g_.m
// Is it okay for gp to panic instead of crashing the program?
// Yes, as long as it is running Go code, not runtime code,
// and not stuck in a system call.
- if gp == nil || gp != _m_.curg {
+ if gp == nil || gp != mp.curg {
return false
}
- if _m_.locks != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
+ if mp.locks != 0 || mp.mallocing != 0 || mp.throwing != 0 || mp.preemptoff != "" || mp.dying != 0 {
return false
}
status := readgstatus(gp)