Repository navigation
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
I can confirm this fixes the flake, which also hit CI on #7408 ( Reproduce on master with: GOGC=1 go test -race -count=200 -run PromptTermination ./cli/command/system ./cli/command/imageThat gave 11 failures on master, and 0 with the write end kept open. Two things you may want to add here:
This is the flake tracked in #5802. |
|
That makes sense. I'll add those changes right now. |
|
@Benehiko anything else you'd like to see here? |
0389b98 to
3f83a0c
Compare
Benehiko
left a comment
There was a problem hiding this comment.
Thanks for tracking this down! The root cause checks out: the discarded write end gets finalized by the GC, and the prompt reads EOF and treats it as "no". Dropping the OutBuffer().Len() check is also safe, since the writer hook only fires after the write to the buffer has completed.
Before this can be merged:
- The commits need to be signed off for the DCO check; none of them currently has a
Signed-off-bytrailer. - Please squash the three commits into one. They are all part of the same fix, and the last one ("fix identical issue in
internal/test/cmd.go") is misleading since that file was already changed in the first commit. A single commit whose message explains the cause (the unreferenced write end is closed by its GC finalizer, so the prompt reads EOF) will be much more useful ingit log.
You can do both at once with git rebase -i --signoff master (mark the later commits as squash), then force-push.
| r, w, err := os.Pipe() | ||
| assert.NilError(t, err) | ||
|
|
||
| // Keep the write end alive for the duration of the test. | ||
| defer w.Close() |
There was a problem hiding this comment.
r is never closed, so every call to TerminatePrompt leaks a file descriptor. Could we register cleanup for both ends of the pipe with t.Cleanup instead of deferring only w.Close()?
| r, w, err := os.Pipe() | |
| assert.NilError(t, err) | |
| // Keep the write end alive for the duration of the test. | |
| defer w.Close() | |
| r, w, err := os.Pipe() | |
| assert.NilError(t, err) | |
| t.Cleanup(func() { | |
| _ = w.Close() | |
| _ = r.Close() | |
| }) |
| r, w, err := os.Pipe() | ||
| assert.NilError(t, err) | ||
|
|
||
| // Keep the write end alive for the duration of the test. | ||
| defer w.Close() |
There was a problem hiding this comment.
Same as in internal/test/cmd.go: r is never closed here either. Could we clean up both ends with t.Cleanup?
| r, w, err := os.Pipe() | |
| assert.NilError(t, err) | |
| // Keep the write end alive for the duration of the test. | |
| defer w.Close() | |
| r, w, err := os.Pipe() | |
| assert.NilError(t, err) | |
| t.Cleanup(func() { | |
| _ = w.Close() | |
| _ = r.Close() | |
| }) |
|
You're welcome! I'll make those changes right now. Thanks for including the |
TerminatePrompt created a pipe for the prompt's stdin but discarded the write end. Once the garbage collector finalized it, the write end was closed, the prompt read EOF and treated it as "no", and the command returned "prune has been cancelled" instead of prompt.ErrTerminated. This keeps both ends of the pipe referenced and closes them in t.Cleanup. This change also drops the OutBuffer().Len() check: the writer hook only fires after the write has completed, so the check proved nothing, and it raced with the prompt's later writes under -race. This change also applies the same fix to the identical copy in cmd/docker-trust. Signed-off-by: Hamir <hirehamir@gmail.com>
3f83a0c to
dd50814
Compare
- What I did
Fixes #5802
- How I did it
I kept the write end of the pipe alive for the duration of the test with
- How to verify it
GOGC=1 GOMEMLIMIT=8MiB)GOGC=off)