From 48f7c70cb1cae85d611efacf3eda9404f57905dc Mon Sep 17 00:00:00 2001 From: Moses Narrow <36607567+0pcom@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:02:11 -0500 Subject: [PATCH] Fix race between Server.Serve() and Server.Close() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If Close() runs before Serve() calls wg.Add(1), the WaitGroup counter is 0, Wait() returns immediately, and then Serve() calls Add(1) on a completed WaitGroup — a data race. Check the done channel before wg.Add(1) so Serve() returns ErrClosed if the server is already shut down. --- pkg/dmsg/server.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/dmsg/server.go b/pkg/dmsg/server.go index 642b0713..9bd4a622 100644 --- a/pkg/dmsg/server.go +++ b/pkg/dmsg/server.go @@ -3,6 +3,7 @@ package dmsg import ( "context" + "errors" "net" "sync" "time" @@ -17,6 +18,9 @@ import ( "github.com/skycoin/dmsg/pkg/dmsg/metrics" ) +// ErrClosed is returned when an operation is attempted on a closed server. +var ErrClosed = errors.New("server closed") + // PeerEntry represents a peer dmsg server to connect to. type PeerEntry struct { PK cipher.PubKey @@ -156,7 +160,12 @@ func (s *Server) Serve(lis net.Listener, addr string) error { WithField("local_pk", s.pk) log.Info("Serving server.") - s.wg.Add(1) + select { + case <-s.done: + return ErrClosed + default: + s.wg.Add(1) + } defer func() { log.Info("Stopped server.") s.wg.Done()