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 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-02-02 04:13:24 +00:00
parent 7fede9d563
commit 3401111aca

View file

@ -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 &copy, 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, &copy)
}
return containers
}