From 56e6439be9552f3dbc28e3896cf6faa1f6defd0e Mon Sep 17 00:00:00 2001 From: Frank Schroeder Date: Tue, 26 Sep 2017 13:42:10 +0200 Subject: [PATCH] fix data race Since state.Checks() returns a shallow copy its elements must not be modified. Copying the elements in the handler does not guarantee consistency since that list is guarded by a different lock. Therefore, the only solution is to have state.Checks() return a deep copy. --- agent/agent_endpoint.go | 1 + agent/local.go | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/agent/agent_endpoint.go b/agent/agent_endpoint.go index 551b9cf071..466f03e07c 100644 --- a/agent/agent_endpoint.go +++ b/agent/agent_endpoint.go @@ -152,6 +152,7 @@ func (s *HTTPServer) AgentChecks(resp http.ResponseWriter, req *http.Request) (i } // Use empty list instead of nil + // checks needs to be a deep copy for this not be racy for _, c := range checks { if c.ServiceTags == nil { c.ServiceTags = make([]string, 0) diff --git a/agent/local.go b/agent/local.go index fdc86142dd..2fe90a1a5f 100644 --- a/agent/local.go +++ b/agent/local.go @@ -341,12 +341,14 @@ func (l *localState) UpdateCheck(checkID types.CheckID, status, output string) { // Checks returns the locally registered checks that the // agent is aware of and are being kept in sync with the server func (l *localState) Checks() map[types.CheckID]*structs.HealthCheck { - checks := make(map[types.CheckID]*structs.HealthCheck) l.RLock() defer l.RUnlock() - for checkID, check := range l.checks { - checks[checkID] = check + checks := make(map[types.CheckID]*structs.HealthCheck) + for id, c := range l.checks { + c2 := new(structs.HealthCheck) + *c2 = *c + checks[id] = c2 } return checks }