From 20fe2f3d08bee14a99806b2b649e0178507b9ca7 Mon Sep 17 00:00:00 2001 From: horus Date: Tue, 19 Dec 2023 21:55:04 +0800 Subject: [PATCH] up: fix write/close race condition in logPrinter The code used an atomic bool to guard channel writes. However, this failed to synchronize with the call to close(), causing a panic. Fix the race condition by using a mutex to guard the update to the bool `stopped` and subsequent channel writes. This ensures atomic execution of both updates to `stopped` and channel writes, preventing races between writes and close(). Signed-off-by: horus --- pkg/compose/printer.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/pkg/compose/printer.go b/pkg/compose/printer.go index c0fd56f7334..dea72e27a68 100644 --- a/pkg/compose/printer.go +++ b/pkg/compose/printer.go @@ -18,7 +18,7 @@ package compose import ( "fmt" - "sync/atomic" + "sync" "github.com/docker/compose/v2/pkg/api" ) @@ -32,9 +32,10 @@ type logPrinter interface { } type printer struct { + sync.Mutex queue chan api.ContainerEvent consumer api.LogConsumer - stopped atomic.Bool + stopped bool } // newLogPrinter builds a LogPrinter passing containers logs to LogConsumer @@ -53,16 +54,21 @@ func (p *printer) Cancel() { } func (p *printer) Stop() { - if p.stopped.CompareAndSwap(false, true) { + p.Lock() + defer p.Unlock() + if !p.stopped { // only close if this is the first call to stop + p.stopped = true close(p.queue) } } func (p *printer) HandleEvent(event api.ContainerEvent) { - // prevent deadlocking, if the printer is done, there's no reader for - // queue, so this write could block indefinitely - if p.stopped.Load() { + p.Lock() + defer p.Unlock() + if p.stopped { + // prevent deadlocking, if the printer is done, there's no reader for + // queue, so this write could block indefinitely return } p.queue <- event