From b7ece91825b2ad3090a027804f899d793314c16e Mon Sep 17 00:00:00 2001 From: Derek Collison Date: Thu, 21 Jun 2018 18:22:06 -0700 Subject: [PATCH] Avoid race by using conditional deep copy Signed-off-by: Derek Collison --- server/client.go | 2 +- server/route.go | 2 +- server/server.go | 14 +++++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/server/client.go b/server/client.go index 02266bff0c..6379dfc83b 100644 --- a/server/client.go +++ b/server/client.go @@ -908,7 +908,7 @@ func (c *client) processPing() { // If there was a cluster update since this client was created, // send an updated INFO protocol now. if srv.lastCURLsUpdate >= c.start.UnixNano() { - c.sendInfo(c.generateClientInfoJSON(srv.info)) + c.sendInfo(c.generateClientInfoJSON(srv.copyInfo())) } c.mu.Unlock() srv.mu.Unlock() diff --git a/server/route.go b/server/route.go index 3e8fb16475..8234583d1a 100644 --- a/server/route.go +++ b/server/route.go @@ -389,7 +389,7 @@ func (s *Server) sendAsyncInfoToClients() { if c.opts.Protocol >= ClientProtoInfo && c.flags.isSet(firstPongSent) { // sendInfo takes care of checking if the connection is still // valid or not, so don't duplicate tests here. - c.sendInfo(c.generateClientInfoJSON(s.info)) + c.sendInfo(c.generateClientInfoJSON(s.copyInfo())) } c.mu.Unlock() } diff --git a/server/server.go b/server/server.go index 081d1eb01a..f1cf44c71f 100644 --- a/server/server.go +++ b/server/server.go @@ -708,6 +708,18 @@ func (s *Server) HTTPHandler() http.Handler { return s.httpHandler } +// Perform a conditional deep copy due to reference nature of ClientConnectURLs. +// If updates are made to Info, this function should be consulted and updated. +// Assume lock is held. +func (s *Server) copyInfo() Info { + info := s.info + if info.ClientConnectURLs != nil { + info.ClientConnectURLs = make([]string, len(s.info.ClientConnectURLs)) + copy(info.ClientConnectURLs, s.info.ClientConnectURLs) + } + return info +} + func (s *Server) createClient(conn net.Conn) *client { // Snapshot server options. opts := s.getOpts() @@ -716,7 +728,7 @@ func (s *Server) createClient(conn net.Conn) *client { // Grab JSON info string s.mu.Lock() - info := s.info + info := s.copyInfo() s.totalClients++ s.mu.Unlock()