Skip to content

Fix data races with shared bytes.Buffer using concurrent.Buffer#2179

Merged
dgageot merged 1 commit intodocker:mainfrom
dgageot:fix-races-buffer
Mar 19, 2026
Merged

Fix data races with shared bytes.Buffer using concurrent.Buffer#2179
dgageot merged 1 commit intodocker:mainfrom
dgageot:fix-races-buffer

Conversation

@dgageot
Copy link
Member

@dgageot dgageot commented Mar 19, 2026

Two independent data races were caused by unsynchronized bytes.Buffer access:

  1. pkg/agent: TestModel_LogsSelection sets the global slog default to a handler backed by a bytes.Buffer. Parallel tests (TestModelOverride, TestModelOverride_ConcurrentAccess) also call Agent.Model() which triggers slog.Info(), racing on the shared buffer.

  2. pkg/tools/builtin: startLocked() uses a bytes.Buffer as cmd.Stderr. The os/exec goroutine writes to it while readNotifications reads and resets it on a ticker.

Introduce concurrent.Buffer — a mutex-protected bytes.Buffer — in the existing pkg/concurrent package (alongside Map and Slice) and use it in both locations.

Assisted-By: docker-agent

Two independent data races were caused by unsynchronized bytes.Buffer access:

1. pkg/agent: TestModel_LogsSelection sets the global slog default to a
   handler backed by a bytes.Buffer. Parallel tests (TestModelOverride,
   TestModelOverride_ConcurrentAccess) also call Agent.Model() which
   triggers slog.Info(), racing on the shared buffer.

2. pkg/tools/builtin: startLocked() uses a bytes.Buffer as cmd.Stderr.
   The os/exec goroutine writes to it while readNotifications reads and
   resets it on a ticker.

Introduce concurrent.Buffer — a mutex-protected bytes.Buffer — in the
existing pkg/concurrent package (alongside Map and Slice) and use it in
both locations.

Assisted-By: docker-agent
@dgageot dgageot requested a review from a team as a code owner March 19, 2026 17:57
Copy link

@docker-agent docker-agent bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟢 APPROVE

This PR correctly fixes two data races by introducing a thread-safe concurrent.Buffer wrapper around bytes.Buffer. The implementation properly uses mutexes to protect all buffer operations (Write, String, Reset, and the atomic Drain method).

Changes reviewed:

  • ✅ New concurrent.Buffer type with proper mutex protection
  • ✅ Test code updated to use concurrent-safe buffer for shared slog handler
  • ✅ LSP stderr handling updated to use concurrent-safe buffer
  • ✅ Atomic Drain() method prevents read-reset race conditions

No bugs found in the changed code. The fix is well-designed and addresses the root cause of the data races described in the PR.

@dgageot dgageot merged commit 31cb345 into docker:main Mar 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants