From 3401111aca18abf61fbf119d6366b13c33d6dc41 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 2 Feb 2026 04:13:24 +0000 Subject: [PATCH] fix(container): prevent data race in State.Get and State.All Return copies of Container structs instead of pointers to the map entries. This prevents data races when containers are modified concurrently by waitForExit and Stop. Fixes #76 Co-Authored-By: Claude Opus 4.5 --- pkg/container/state.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/container/state.go b/pkg/container/state.go index 53ab1e2a..b8d98b97 100644 --- a/pkg/container/state.go +++ b/pkg/container/state.go @@ -99,13 +99,19 @@ func (s *State) Add(c *Container) error { return s.SaveState() } -// Get retrieves a container by ID. +// Get retrieves a copy of a container by ID. +// Returns a copy to prevent data races when the container is modified. func (s *State) Get(id string) (*Container, bool) { s.mu.RLock() defer s.mu.RUnlock() c, ok := s.Containers[id] - return c, ok + if !ok { + return nil, false + } + // Return a copy to prevent data races + copy := *c + return ©, true } // Update updates a container in the state and persists it. @@ -126,14 +132,16 @@ func (s *State) Remove(id string) error { return s.SaveState() } -// All returns all containers in the state. +// All returns copies of all containers in the state. +// Returns copies to prevent data races when containers are modified. func (s *State) All() []*Container { s.mu.RLock() defer s.mu.RUnlock() containers := make([]*Container, 0, len(s.Containers)) for _, c := range s.Containers { - containers = append(containers, c) + copy := *c + containers = append(containers, ©) } return containers }