Skip to content

Fix shim fully drain stdin on close IO#246

Open
austinvazquez wants to merge 3 commits into
containerd:mainfrom
austinvazquez:fix/fully-drain-io-copystreams
Open

Fix shim fully drain stdin on close IO#246
austinvazquez wants to merge 3 commits into
containerd:mainfrom
austinvazquez:fix/fully-drain-io-copystreams

Conversation

@austinvazquez

@austinvazquez austinvazquez commented Jul 2, 2026

Copy link
Copy Markdown
Member

This change addresses an edge case where draining stdin on close will truncate data. Attempt to read until EOF and bind the read with a timeout (currently 2 seconds which should only occur for bad clients that trigger CloseIO without close the pipe's write end)

Ref: https://github.com/containerd/nerdbox/actions/runs/28613973997/job/84853144969?pr=245

--- FAIL: TestShim (44.19s)
    --- FAIL: TestShim/LargeStdioRoundTrip (0.48s)
        exec_suite.go:743: got 20959232 bytes, want 20971520 (truncated by 12288 bytes)

Copilot AI review requested due to automatic review settings July 2, 2026 19:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the shim’s stdin forwarding logic to ensure that when CloseIO fires, any remaining bytes already buffered on the stdin reader are fully drained and forwarded before the shim sends an in-band EOF (CloseWrite) to the guest.

Changes:

  • Replace the single “drain one read” behavior on CloseIO with a loop that continues reading/writing until the stdin reader returns EOF or an error.
  • Expand the in-code rationale to document why a single read can truncate stdin under backpressure (e.g., slow guest consumption / vsock credit).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/shim/task/io_copystreams.go Outdated
Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>
Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>
@austinvazquez austinvazquez force-pushed the fix/fully-drain-io-copystreams branch from cc0a1a4 to 2316bcb Compare July 2, 2026 22:04
Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>
@austinvazquez austinvazquez force-pushed the fix/fully-drain-io-copystreams branch from 2316bcb to f054a26 Compare July 2, 2026 22:23
Copilot AI review requested due to automatic review settings July 2, 2026 22:23
@austinvazquez austinvazquez marked this pull request as ready for review July 2, 2026 22:23
@austinvazquez austinvazquez changed the title fix(task): fully drain stdin on close Fix shim fully drain stdin on close IO Jul 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +62 to 86
for draining := true; draining; {
select {
case res := <-readCh:
if res.n > 0 {
if _, err := sc.Write(buf[:res.n]); err != nil {
log.G(ctx).WithError(err).Warn("error writing stdin on CloseIO")
draining = false
break
}
}
if res.err != nil {
// EOF (write end closed) or read error: fully drained.
draining = false
break
}
// More may be buffered; continue to drain.
go read()
case <-time.After(stdinDrainGrace):
// Stalled draining the buffer; EOF not yet reached.
log.G(ctx).Warn("stdin drain stalled after CloseIO; signaling EOF without client write-end close")
f.Close()
<-readCh
draining = false
}
}
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