aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2025-05-09 16:18:49 -0700
committerGopher Robot <gobot@golang.org>2025-05-20 12:36:34 -0700
commitd596bc0e819aec2cf65a61d8b92f6bec8e0a7124 (patch)
tree14c158aaf6d5181ff698ff7d5f631961f129cfc4 /src
parentb7382cc1f012016c91036c49db0ea6db444b47d8 (diff)
downloadgo-d596bc0e819aec2cf65a61d8b92f6bec8e0a7124.tar.xz
runtime: disallow closing bubbled chans from outside bubble
A chan created within a synctest bubble may not be operated on from outside the bubble. We panicked on send and receive, but not close. Panic on close as well. For #67434 Change-Id: I98d39e0cf7baa1a679aca1fb325453d69c535308 Reviewed-on: https://go-review.googlesource.com/c/go/+/671960 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Damien Neil <dneil@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/internal/synctest/synctest_test.go40
-rw-r--r--src/runtime/chan.go3
2 files changed, 43 insertions, 0 deletions
diff --git a/src/internal/synctest/synctest_test.go b/src/internal/synctest/synctest_test.go
index c0e126e3fc..7c8fd7ef9e 100644
--- a/src/internal/synctest/synctest_test.go
+++ b/src/internal/synctest/synctest_test.go
@@ -263,6 +263,46 @@ func TestChannelFromOutsideBubble(t *testing.T) {
}
}
+func TestChannelMovedOutOfBubble(t *testing.T) {
+ for _, test := range []struct {
+ desc string
+ f func(chan struct{})
+ wantPanic string
+ }{{
+ desc: "receive",
+ f: func(ch chan struct{}) {
+ <-ch
+ },
+ wantPanic: "receive on synctest channel from outside bubble",
+ }, {
+ desc: "send",
+ f: func(ch chan struct{}) {
+ ch <- struct{}{}
+ },
+ wantPanic: "send on synctest channel from outside bubble",
+ }, {
+ desc: "close",
+ f: func(ch chan struct{}) {
+ close(ch)
+ },
+ wantPanic: "close of synctest channel from outside bubble",
+ }} {
+ t.Run(test.desc, func(t *testing.T) {
+ donec := make(chan struct{})
+ ch := make(chan chan struct{})
+ go func() {
+ defer close(donec)
+ defer wantPanic(t, test.wantPanic)
+ test.f(<-ch)
+ }()
+ synctest.Run(func() {
+ ch <- make(chan struct{})
+ })
+ <-donec
+ })
+ }
+}
+
func TestTimerFromInsideBubble(t *testing.T) {
for _, test := range []struct {
desc string
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index cb2737d096..63d8044b44 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -415,6 +415,9 @@ func closechan(c *hchan) {
if c == nil {
panic(plainError("close of nil channel"))
}
+ if c.synctest && getg().bubble == nil {
+ panic(plainError("close of synctest channel from outside bubble"))
+ }
lock(&c.lock)
if c.closed != 0 {