-
Notifications
You must be signed in to change notification settings - Fork 0
7639: io: fix the hang-forever issue of Mock when the write buf is empty
#24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: ADD-SP <[email protected]>
Co-authored-by: Martin Grigorov <[email protected]>
WalkthroughThis pull request updates the tokio-test crate's Mock I/O implementation and test suite. A new dev-dependency ( ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Pull Request Review: Fix hang-forever issue in
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review completed. 1 suggestions posted.
Comment augment review to trigger a new review at any time.
| panic!("unexpected WouldBlock {}", self.pmsg()); | ||
| } | ||
| } | ||
| Ok(0) if buf.is_empty() => return Poll::Ready(Ok(0)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider short‑circuiting on an empty buf before calling self.inner.write(buf) so zero‑length writes return immediately even when a Wait action is pending; currently, a zero‑length write during Wait will still be delayed by the sleep. This aligns with typical AsyncWrite semantics where writing 0 bytes should not block.
🤖 Was this useful? React with 👍 or 👎
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value:incorrect-but-reasonable; category:bug; feedback:The Augment AI reviewer is not correct! There is an extra logic in the Mock that deals with timers and other extra actions which should be handled before doing the "write" operation, so there is no much benefit of moving the check earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
tokio-test/Cargo.toml(1 hunks)tokio-test/src/io.rs(4 hunks)tokio-test/tests/io.rs(2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: martin-augment
Repo: martin-augment/tokio PR: 13
File: tokio-util/src/io/simplex.rs:184-209
Timestamp: 2025-11-05T14:24:03.551Z
Learning: In AsyncWrite implementations, zero-length writes (when buf.is_empty()) should return Poll::Ready(Ok(0)) immediately without blocking or registering wakers. Only non-empty buffers that cannot be written due to backpressure should return Poll::Pending. This prevents indefinite hangs when empty slices are written.
📚 Learning: 2025-11-05T14:24:03.551Z
Learnt from: martin-augment
Repo: martin-augment/tokio PR: 13
File: tokio-util/src/io/simplex.rs:184-209
Timestamp: 2025-11-05T14:24:03.551Z
Learning: In AsyncWrite implementations, zero-length writes (when buf.is_empty()) should return Poll::Ready(Ok(0)) immediately without blocking or registering wakers. Only non-empty buffers that cannot be written due to backpressure should return Poll::Pending. This prevents indefinite hangs when empty slices are written.
Applied to files:
tokio-test/tests/io.rstokio-test/src/io.rs
📚 Learning: 2025-10-28T15:30:50.368Z
Learnt from: martin-augment
Repo: martin-augment/tokio PR: 9
File: tokio/src/fs/file.rs:824-855
Timestamp: 2025-10-28T15:30:50.368Z
Learning: In io-uring write implementations for tokio::fs::File, writes must loop until the buffer is fully drained. A single Op::write_at call may perform a partial write. The code must: (1) loop calling Op::write_at until buf.is_empty(), (2) return io::ErrorKind::WriteZero when 0 bytes are written, (3) only return Operation::Write(Ok(())) after the buffer is completely empty. This applies to both poll_write and poll_write_vectored implementations.
Applied to files:
tokio-test/tests/io.rstokio-test/src/io.rs
📚 Learning: 2025-10-28T15:30:54.516Z
Learnt from: martin-augment
Repo: martin-augment/tokio PR: 9
File: tokio/src/fs/file.rs:970-981
Timestamp: 2025-10-28T15:30:54.516Z
Learning: In tokio fs file io-uring write operations (both vectored and non-vectored), the write must loop until the buffer is fully drained. Operation::Write(Ok()) should only be returned when buf.is_empty() is true. If 0 bytes are written, return Operation::Write(Err(io::ErrorKind::WriteZero.into())). Otherwise, continue executing new writes until the buffer is empty or an error occurs.
Applied to files:
tokio-test/src/io.rs
📚 Learning: 2025-10-30T14:46:01.443Z
Learnt from: martin-augment
Repo: martin-augment/tokio PR: 10
File: tokio-util/src/io/mod.rs:17-17
Timestamp: 2025-10-30T14:46:01.443Z
Learning: In tokio-util, the entire `io` module at `tokio-util/src/lib.rs` is already gated with `cfg_io!` macro, which applies `#[cfg(feature = "io")]` to all contents. Submodules declared within `tokio-util/src/io/mod.rs` inherit this feature gate and don't need additional `cfg_io!` wrapping unless they have specific requirements. The `cfg_io_util!` macro in the same file is for items that specifically require the `io-util` feature, not the general `io` feature.
Applied to files:
tokio-test/Cargo.toml
🧬 Code graph analysis (1)
tokio-test/tests/io.rs (1)
tokio-test/src/io.rs (2)
new(80-82)new(195-212)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: claude-review
🔇 Additional comments (9)
tokio-test/src/io.rs (4)
238-240: LGTM! Pattern matching refinement improves clarity.The explicit enumeration of
Write,WriteError, andWaitas would-block conditions for reads makes the logic clearer than the previous catch-all pattern. This ensures that only write-related or wait actions block read operations, which is the correct behavior.
285-285: LGTM! Explicit pattern makes the no-op behavior clear.Making
ReadandReadErroractions explicit no-ops during write operations improves code clarity. The write loop correctly skips over read-related actions to find the next write action.
444-444: Excellent fix! Zero-length writes now return immediately.This fast-path correctly prevents indefinite hangs when empty buffers are written. The check
Ok(0) if buf.is_empty()ensures that zero-length writes returnPoll::Ready(Ok(0))immediately without blocking or registering wakers, which is the expected behavior for AsyncWrite implementations.Based on learnings
498-498: LGTM! Explicit enumeration in Drop is clearer.The explicit pattern matching for
ReadError,WriteError, andWaitactions makes it clear that these don't require assertions during drop. OnlyReadandWriteactions need to verify that their data is fully consumed.tokio-test/tests/io.rs (5)
3-11: LGTM! Imports are necessary for the new tests.All the new imports are appropriately used in the added test cases for manual polling and assertion utilities.
180-203: Good documentation of known bug.This test correctly documents the hang-forever behavior when reading with no sequenced read action. The use of
panic_wakerensures the test will catch if this bug is fixed (intentionally or unintentionally). The extensive comments explain the rationale for not fixing this yet.
205-219: Good regression test for documented behavior.This test correctly captures the current behavior where unconsumed error actions don't cause panics. The TODO comment appropriately marks this as something to address in a future major release.
221-246: Well-documented test for builder cloning issue.This test correctly demonstrates the panic that occurs when cloning a builder with error actions due to the
Arc::try_unwrapcall failing when multiple references exist. The detailed comments explain why this isn't fixed yet (would require breaking changes).
248-259: Excellent test for the zero-length write fix!This test directly verifies that zero-length writes return
Poll::Ready(Ok(0))immediately without hanging. The use of manual polling withpoll_writeis the correct approach to test this behavior. The follow-upwrite_allappropriately drains the remaining action to prevent a panic during drop.Based on learnings
| [dev-dependencies] | ||
| tokio = { version = "1.2.0", path = "../tokio", features = ["full"] } | ||
| futures-util = "0.3.0" | ||
| futures-test = "0.3.5" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify that this is the latest version of futures-test.
The version 0.3.5 appears to be from 2020. Ensure you're using the latest available version for security and compatibility with other dependencies.
🏁 Script executed:
#!/bin/bash
# Check for the latest version of futures-test on crates.io
curl -s https://crates.io/api/v1/crates/futures-test | jq -r '.crate.max_stable_version'Length of output: 6
Update futures-test dependency to the latest version.
The version 0.3.5 is significantly outdated. Update to 0.3.31 (the latest stable version) for security, bug fixes, and compatibility improvements.
🤖 Prompt for AI Agents
In tokio-test/Cargo.toml around line 27, the futures-test dependency is pinned
to the outdated version "0.3.5"; update the dependency line to use the newer
stable version "0.3.31" (i.e., replace 0.3.5 with 0.3.31) and run cargo update
or cargo build to refresh lockfile and verify compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value:useful; category:bug; feedback:The CodeRabbit AI reviewer is correct that the version of the futures-test dependency is very old and should be updated to a newer one. It is used only in the tests for it does not bring any security related concerns.
value:good-to-have; category:bug; feedback:The Claude AI reviewer is correct that by using a version ending on ".0" cargo will use the latest available, e.g. "0.3.0" will resolve to the latest available 0.3.x |
7639: To review by AI