Conversation
…z timeout When go test -fuzz -fuzztime=30s completes its budget, Go cancels t.Context(). Previously, fuzz iterations derived their context from context.Background(), so an in-flight iteration would hit its own 5s per-iteration deadline at the fuzz-time boundary, return context.DeadlineExceeded, and the test would call t.Fatal() — reporting a spurious CI failure. Two-part fix across all fuzz test files: 1. Check t.Context().Err() at the top of every f.Fuzz body; return immediately if fuzz time has already elapsed. 2. Derive per-iteration contexts from t.Context() so they are cancelled when fuzz time ends, and treat context cancellation as a clean exit rather than a test failure by adding t.Context().Err() guards before every t.Errorf/t.Fatalf call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When -fuzztime=30s expires, Go's internal fuzz coordinator cancels any in-flight worker iteration and emits "context deadline exceeded" with no file:line reference. This is not a test failure — it's the normal fuzz time boundary. Real test assertion failures always include a file:line reference (e.g. foo_test.go:42:). Wrap all fuzz invocations in a fuzz_run() helper that: 1. Captures output and exit code 2. If exit non-zero, checks for file:line references in the output 3. If no file:line found, treats as boundary timeout and exits 0 4. If file:line found, propagates the real failure Also reduces per-invocation -timeout from 300s to 90s (30s fuzz + 60s grace) since each go test call fuzzes exactly one function. Applies to both the fuzz and fuzz-differential CI jobs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The PPID chain walk only guarded against immediate self-reference (p.PPID == cur) but not longer cycles like A→B→C→A. On Windows CI the process table can contain such cycles, causing FuzzPSFlags to hang indefinitely in the seed corpus run. Replace the narrow self-reference check with a visited set that detects any cycle in the PPID chain. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
With bash -e active in GitHub Actions, output=$(go test ...) causes the entire function to exit immediately when go test returns non-zero. This meant: - echo "$output" never ran (no visible log output) - The grep check for real failures never ran - The step silently failed rather than logging what went wrong Replace with tee to a tmpfile so: 1. go test output streams live to the Actions log in real time 2. PIPESTATUS[0] correctly captures go test's exit code 3. The tmpfile is available for grep after the command finishes Applies to both fuzz and fuzz-differential jobs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
matt-dz
approved these changes
Mar 26, 2026
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.
Problem
Fuzz CI was failing in multiple ways:
Coordinator boundary timeout — When
-fuzztime=30sexpires, Go's internal fuzz coordinator cancels any in-flight worker iteration and emitscontext deadline exceededwith no file:line reference. This is not a test failure, but the CI step was treating it as one.Test context not derived from
t.Context()— Fuzz iterations usedcontext.WithTimeout(context.Background(), 5s)instead of deriving fromt.Context(). This meant an in-flight iteration at the 30s boundary would hit its own deadline, returncontext.DeadlineExceeded, and callt.Fatal()— causing a spurious CI failure.FuzzPSFlagshanging on Windows —getSessioninprocinfo_windows.gowalked the PPID chain with only an immediate self-reference guard (p.PPID == cur). On Windows CI the process table can contain longer PPID cycles (A→B→C→A), causing an infinite loop that hung for the full 120s seed corpus timeout.Fix
1. Fuzz test context propagation (18 files)
f.Fuzzbody:if t.Context().Err() != nil { return }t.Context()so cancellation propagates when fuzz time ends2. CI workflow boundary timeout handling (
.github/workflows/fuzz.yml)Wrap all
go test -fuzz=...invocations in afuzz_run()shell helper that:_test.go:NNN:file:line references — real assertion failures always have these; coordinator boundary timeouts don'tAlso reduces per-invocation
-timeoutfrom 300s (shared across all functions) to 90s (30s fuzz + 60s grace per function call).Applies to both
fuzzandfuzz-differentialCI jobs.3.
procinfo_windows.goPPID cycle detectionReplace the narrow self-reference guard with a proper visited set:
Test plan
context deadline exceededfailures)Fuzz seed corpus (windows-latest)passes (FuzzPSFlagsno longer hangs)Fuzz Differential (wc)passes consistently🤖 Generated with Claude Code