Repository navigation
fix(zapcore): ignore invalid stdio sync handles on Windows - #1595
sb123sb123 wants to merge 1 commit into
Conversation
|
|
otrumb
left a comment
There was a problem hiding this comment.
The Windows-specific error filtering is appropriately narrow for direct Lock(os.Stdout) and Lock(os.Stderr) calls: wrapped ERROR_INVALID_HANDLE is ignored, while ordinary files and unrelated errors still propagate.
However, the fix does not cover zap's documented high-level stdout/stderr path or composed write syncers. lockWriteSyncer only recognizes a direct *os.File, but Open("stdout") returns a nopCloserSink and CombineWriteSyncers passes the resulting wrapper or multiWriteSyncer into Lock.
On Windows with CGO_ENABLED=0, after reassigning os.Stdout to a pipe and closing its handle:
Open("stdout").Sync()still returnssync |1: The handle is invalid.Lock(NewMultiWriteSyncer(os.Stdout, os.Stdout)).Sync()returns two invalid-handle errors.
Please apply the stdio adaptation to each current stdout/stderr member before wrapper or multi-writer composition. Regression tests should cover Open("stdout"), duplicate/mixed write syncers, and verify another core still receives Sync and propagates its unrelated error.
Fixes #991
Rationale
On Windows, syncing a closed standard-output or standard-error handle returns an
*fs.PathErrorwrappingERROR_INVALID_HANDLE(syscall.Errno(6)).zapcore.Lock(os.Stdout)currently propagates that expected shutdown condition, even when other cores still need their realSynccalls.This change wraps only the current
os.Stdoutandos.Stderr*os.Filevalues when passed throughzapcore.Lock, ignores onlyERROR_INVALID_HANDLEfrom those wrappers, and preserves all other sync errors and regular-file behavior. Non-Windows builds keep the existing behavior.Tests
Windows amd64, Go 1.26.8:
go.exe run zap-991-repro.goreturnedraw os.File.Sync after closing stdout handle: *fs.PathError: sync |1: The handle is invalid.go.exe test -modfile=zap-991-test.mod ./zapcore -count=1 -run 'TestLock(StdioSyncIgnoresInvalidHandle|RegularFileSyncPropagatesInvalidHandle)$' -v— PASS; stdout, stderr, and regular-file subtests passed.go.exe vet -modfile=zap-991-test.mod ./zapcore— PASS.GOOS=linux GOARCH=amd64 go.exe test -modfile=zap-991-test.mod ./zapcore -run '^$' -c -o zap-991-linux.test— PASS.The focused commands used a task-local temporary modfile and the task-provided module cache because direct access to
proxy.golang.orgtimed out on this host.Limitations
go.exe test -modfile=zap-991-test.mod ./zapcore -count=1remains red on this Windows checkout only inTestIOCore, wheretesting.TempDircannot remove a log file still held open by another process.go.exe test -modfile=zap-991-test.mod ./...also retains the checkout's unrelated Windows failures inTestConfig,TestConfigWithSamplingHook,TestOpen,TestOpenOtherErrors,TestStacktraceFiltersVendorZap,Example_basicConfiguration, andzapcore.TestIOCore.AI assistance: OpenAI Codex (GPT-5.6 Luna).