Fix nil pointer dereference in Windows pipe writer Close - #397
Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 3 commits intoAug 14, 2026
Merged
Conversation
Guard against a nil connection in pipeWriter.Close(). The writer defers connection setup to the first write, so conn is nil until then, and closing a client that never wrote panicked with a nil pointer dereference. This mirrors the guard udsWriter.Close() already has. Read conn under p.mu rather than directly: Write() nils the field out under a write lock when a non-temporary error disconnects it, so an unsynchronized read in Close() is a data race. Signed-off-by: Mohammad Rafi <mohammad.rafi@datadoghq.com>
|
🎯 Code Coverage (details) 🔗 Commit SHA: c3f1f6e | Docs | Datadog PR Page | Give us feedback! |
mrafi97
marked this pull request as ready for review
August 14, 2026 16:35
rayz
previously approved these changes
Aug 14, 2026
jszwedko
reviewed
Aug 14, 2026
Co-authored-by: Jesse Szwedko <jesse@szwedko.me>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rayz
approved these changes
Aug 14, 2026
This was referenced Aug 14, 2026
Merged
gh-worker-dd-mergequeue-cf854d Bot
pushed a commit
to DataDog/datadog-agent
that referenced
this pull request
Aug 17, 2026
### What does this PR do? - Upgrades `github.com/DataDog/datadog-go/v5` from `v5.9.0` to `v5.9.1` across the Go workspace. ### Motivation [#incident-59243](https://dd.enterprise.slack.com/archives/C0BQAB1T274) https://datadoghq.atlassian.net/browse/WINA-3031 `datadog-go v5.9.1` fixes a nil pointer dereference in the Windows named-pipe writer (DataDog/datadog-go#397). The pipe connection is established on first write, so closing a client that never successfully wrote dereferenced a nil `net.Conn` and terminated the process. The Agent Data Plane pre-flight probe triggers this on Windows. It dials the pipe once to prove readiness, then the statsd client dials again on its first write; when that second dial loses a startup race, the deferred `client.Close()` crashed the Agent service with `0xc0000005`. This is intermittent by nature — it needs the first dial to succeed and the second to fail. ### Describe how you validated your changes - `go list -m github.com/DataDog/datadog-go/v5` resolves to `v5.9.1`. - `go mod verify` — all modules verified. - `GOOS=windows go build ./comp/dataplane/...` passes. The fix is in a `//go:build windows` file, so a native build would not exercise it. - Confirmed every changed `go.mod`/`go.sum` line is datadog-go and nothing else. ### Additional Notes Renovate normally owns this bump (it did v5.9.0 in #53234), but `minimumReleaseAge: 7 days` means it would not open a PR until ~2026-08-24. Landing it manually since the crash blocks 7.84. The diff matches Renovate's output file-for-file, so it will simply see the dependency as current. Co-authored-by: mohammad.rafi <mohammad.rafi@datadoghq.com>
github-actions Bot
pushed a commit
to DataDog/datadog-agent
that referenced
this pull request
Aug 17, 2026
### What does this PR do? - Upgrades `github.com/DataDog/datadog-go/v5` from `v5.9.0` to `v5.9.1` across the Go workspace. ### Motivation [#incident-59243](https://dd.enterprise.slack.com/archives/C0BQAB1T274) https://datadoghq.atlassian.net/browse/WINA-3031 `datadog-go v5.9.1` fixes a nil pointer dereference in the Windows named-pipe writer (DataDog/datadog-go#397). The pipe connection is established on first write, so closing a client that never successfully wrote dereferenced a nil `net.Conn` and terminated the process. The Agent Data Plane pre-flight probe triggers this on Windows. It dials the pipe once to prove readiness, then the statsd client dials again on its first write; when that second dial loses a startup race, the deferred `client.Close()` crashed the Agent service with `0xc0000005`. This is intermittent by nature — it needs the first dial to succeed and the second to fail. ### Describe how you validated your changes - `go list -m github.com/DataDog/datadog-go/v5` resolves to `v5.9.1`. - `go mod verify` — all modules verified. - `GOOS=windows go build ./comp/dataplane/...` passes. The fix is in a `//go:build windows` file, so a native build would not exercise it. - Confirmed every changed `go.mod`/`go.sum` line is datadog-go and nothing else. ### Additional Notes Renovate normally owns this bump (it did v5.9.0 in #53234), but `minimumReleaseAge: 7 days` means it would not open a PR until ~2026-08-24. Landing it manually since the crash blocks 7.84. The diff matches Renovate's output file-for-file, so it will simply see the dependency as current. Co-authored-by: mohammad.rafi <mohammad.rafi@datadoghq.com> 4718b57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds a nil guard to
pipeWriter.Close()on Windows.newWindowsPipeWriterdeliberately defers connection setup to the firstwrite, so
connis nil until then. Closing a client that never wrotedereferenced that nil connection and panicked.
udsWriter.Close()already has this exact guard; this brings the pipe writer in line.
The connection is now read under
p.murather than directly, becauseWrite()nils the field out under a write lock when a non-temporaryerror disconnects it — an unsynchronized read in
Close()is a datarace.
Motivation
#incident-59243
https://datadoghq.atlassian.net/browse/WINA-3031
Found via a crashing Windows service in datadog-agent. Its pre-flight
mode component dials the named pipe once to probe readiness, then the
statsd client dials again on first write. When that second dial loses a
startup race, the deferred
client.Close()took down the process with0xc0000005— a read of address0x18, i.e. a method call through anil interface.
Not a recent regression:
conn: nildates to c995f1b (March 2021,first released in v4.5.0), and
pipe_windows.gois byte-identicalbetween v5.8.3 and v5.9.0. It had simply never had a caller that closes
a client which never successfully wrote.
Testing
Adds
TestPipeWriterCloseWithoutWrite, which constructs a writer andcloses it without writing — this panics on the current code. Verified
go vetand a test binary build underGOOS=windows; the pipe teststhemselves need a real Windows named pipe, so they only execute on a
Windows runner.