aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2025-08-14 10:27:54 -0700
committerGopher Robot <gobot@golang.org>2025-08-14 12:20:59 -0700
commita8564bd412d4495a6048f981d30d4d7abb1e45a7 (patch)
treeaa69dbad941308b1b6817cd313d9746d3c9d3349 /src/runtime
parent924fe98902cdebf20825ab5d1e4edfc0fed2966f (diff)
downloadgo-a8564bd412d4495a6048f981d30d4d7abb1e45a7.tar.xz
runtime: make all synctest bubble violations fatal panics
Unblocking a bubbled goroutine from outside the bubble is an error and panics. Currently, some of those panics are regular panics and some are fatal. We use fatal panics in cases where its difficult to panic without leaving something in an inconsistent state. Change the regular panics (channel and timer operations) to be fatal. This makes our behavior more consistent: All bubble violations are always fatal. More importantly, it avoids introducing new, recoverable panics. A motivating example for this change is the context package, which performs channel operations with a mutex held in the expectation that those operations can never panic. These operations can now panic as a result of a bubble violation, potentially leaving a context.Context in an inconsistent state. Fixes #74837 Change-Id: Ie6efd916b7f505c0f13dde42de1572992401f15c Reviewed-on: https://go-review.googlesource.com/c/go/+/696195 Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/chan.go10
-rw-r--r--src/runtime/select.go2
-rw-r--r--src/runtime/time.go4
3 files changed, 8 insertions, 8 deletions
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index bb554ebfdb..639d29dc83 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -191,7 +191,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
}
if c.bubble != nil && getg().bubble != c.bubble {
- panic(plainError("send on synctest channel from outside bubble"))
+ fatal("send on synctest channel from outside bubble")
}
// Fast path: check for failed non-blocking operation without acquiring the lock.
@@ -318,7 +318,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
if c.bubble != nil && getg().bubble != c.bubble {
unlockf()
- panic(plainError("send on synctest channel from outside bubble"))
+ fatal("send on synctest channel from outside bubble")
}
if raceenabled {
if c.dataqsiz == 0 {
@@ -416,7 +416,7 @@ func closechan(c *hchan) {
panic(plainError("close of nil channel"))
}
if c.bubble != nil && getg().bubble != c.bubble {
- panic(plainError("close of synctest channel from outside bubble"))
+ fatal("close of synctest channel from outside bubble")
}
lock(&c.lock)
@@ -538,7 +538,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
}
if c.bubble != nil && getg().bubble != c.bubble {
- panic(plainError("receive on synctest channel from outside bubble"))
+ fatal("receive on synctest channel from outside bubble")
}
if c.timer != nil {
@@ -702,7 +702,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {
if c.bubble != nil && getg().bubble != c.bubble {
unlockf()
- panic(plainError("receive on synctest channel from outside bubble"))
+ fatal("receive on synctest channel from outside bubble")
}
if c.dataqsiz == 0 {
if raceenabled {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index ae7754b173..113dc8ad19 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -178,7 +178,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
if cas.c.bubble != nil {
if getg().bubble != cas.c.bubble {
- panic(plainError("select on synctest channel from outside bubble"))
+ fatal("select on synctest channel from outside bubble")
}
} else {
allSynctest = false
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 4880dce8cd..e9d1f0b6c9 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -415,7 +415,7 @@ func newTimer(when, period int64, f func(arg any, seq uintptr, delay int64), arg
//go:linkname stopTimer time.stopTimer
func stopTimer(t *timeTimer) bool {
if t.isFake && getg().bubble == nil {
- panic("stop of synctest timer from outside bubble")
+ fatal("stop of synctest timer from outside bubble")
}
return t.stop()
}
@@ -430,7 +430,7 @@ func resetTimer(t *timeTimer, when, period int64) bool {
racerelease(unsafe.Pointer(&t.timer))
}
if t.isFake && getg().bubble == nil {
- panic("reset of synctest timer from outside bubble")
+ fatal("reset of synctest timer from outside bubble")
}
return t.reset(when, period)
}