From d596bc0e819aec2cf65a61d8b92f6bec8e0a7124 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 9 May 2025 16:18:49 -0700 Subject: [PATCH] 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 Reviewed-by: Michael Pratt Auto-Submit: Damien Neil --- src/internal/synctest/synctest_test.go | 40 ++++++++++++++++++++++++++ src/runtime/chan.go | 3 ++ 2 files changed, 43 insertions(+) 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 { -- 2.51.0