]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: disallow closing bubbled chans from outside bubble
authorDamien Neil <dneil@google.com>
Fri, 9 May 2025 23:18:49 +0000 (16:18 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 20 May 2025 19:36:34 +0000 (12:36 -0700)
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>

src/internal/synctest/synctest_test.go
src/runtime/chan.go

index c0e126e3fcd77be7d2923a9cb9b885c9ea130ce8..7c8fd7ef9e83da458fc22b8a8a93c7db166acf9b 100644 (file)
@@ -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
index cb2737d096328411ceeb37c26a6c21f20621aebd..63d8044b44d54e5da18ffa9142525400da4b765e 100644 (file)
@@ -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 {