From 14892a73a904bbc8195ed6994d57ca2ef4e45524 Mon Sep 17 00:00:00 2001 From: Denis Peshkov Date: Thu, 14 Aug 2025 22:33:55 +0400 Subject: [PATCH] Fix panic in multiListener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If Close() is called concurrently, both goroutines could pass the select’s default case before either of them executes close(), resulting in the channel being closed twice --- net/multi_listen.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/multi_listen.go b/net/multi_listen.go index 7cb7795b..e5d50805 100644 --- a/net/multi_listen.go +++ b/net/multi_listen.go @@ -21,6 +21,7 @@ import ( "fmt" "net" "sync" + "sync/atomic" ) // connErrPair pairs conn and error which is returned by accept on sub-listeners. @@ -38,6 +39,7 @@ type multiListener struct { connCh chan connErrPair // stopCh communicates from parent to child listeners. stopCh chan struct{} + closed atomic.Bool } // compile time check to ensure *multiListener implements net.Listener @@ -150,10 +152,8 @@ func (ml *multiListener) Accept() (net.Conn, error) { // the go-routines to exit. func (ml *multiListener) Close() error { // Make sure this can be called repeatedly without explosions. - select { - case <-ml.stopCh: + if !ml.closed.CompareAndSwap(false, true) { return fmt.Errorf("use of closed network connection") - default: } // Tell all sub-listeners to stop.