libsmol opened issue #14986:
Summary
On WASIp2, a TCP
input-streamcan report itself ready before the peer has sent anything:subscribe().ready()returnstrueright after the connection is set up. A guest that waits on the pollable and then does a blocking read ends up blocking in the read instead, and in some embeddings wasi-libc'spoll()reports an idle socket as readable.Reproduction
With the
setuphelper fromcrates/test-programs/src/bin/p2_tcp_streams.rs:
rust setup(net, family, |server, client| { // Nothing has been sent in either direction, yet this fails: assert!(!client.input.subscribe().ready()); });On
main(ffff2e2) this fails in bothp2::sync::p2_tcp_streamsandp2::async_::p2_tcp_streams. The accompanying pull request adds it as a test.Through wasi-libc, in an embedder that uses
wasmtime_wasi::p2::add_to_linker_syncwith Wasmtime 50.0.0: after accepting a connection whose peer never sends,poll()withPOLLINand a one-second timeout returns 1 immediately withrevents == POLLIN, although there is nothing to read. I couldn't reproduce this second case through thewasmtimeCLI with the same program.Both were observed on Linux (aarch64).
Cause
TcpReceiveStream::poll_readyincrates/wasi/src/sockets/tcp.rsreturnstokio::net::TcpStream::poll_read_ready, which reflects tokio's cached readiness. Tokio clears read readiness only when an operation returnsWouldBlock, and for these sockets it can already be set before any data has arrived. In a standalone tokio program, for example, a stream returned byTcpListener::acceptis reported readable before anything has been sent, whilepoll_peekon the same stream correctly returnsPending.Proposed fix
I'll open a pull request that makes
poll_readypeek a single byte, which waits for data, the end of the stream or an error, and clears tokio's readiness when there's nothing to read yet. Happy to take a different approach if you'd prefer.
This issue and the accompanying pull request were prepared by an AI coding assistant (Claude Code, running Anthropic's Claude Opus 5.5) on behalf of the libsmol project, which ran into this while running RustPython under Wasmtime. We've tried to verify everything described here, but please let us know if anything looks off or unclear.
tschneidereit closed issue #14986:
Summary
On WASIp2, a TCP
input-streamcan report itself ready before the peer has sent anything:subscribe().ready()returnstrueright after the connection is set up. A guest that waits on the pollable and then does a blocking read ends up blocking in the read instead, and in some embeddings wasi-libc'spoll()reports an idle socket as readable.Reproduction
With the
setuphelper fromcrates/test-programs/src/bin/p2_tcp_streams.rs:
rust setup(net, family, |server, client| { // Nothing has been sent in either direction, yet this fails: assert!(!client.input.subscribe().ready()); });On
main(ffff2e2) this fails in bothp2::sync::p2_tcp_streamsandp2::async_::p2_tcp_streams. The accompanying pull request adds it as a test.Through wasi-libc, in an embedder that uses
wasmtime_wasi::p2::add_to_linker_syncwith Wasmtime 50.0.0: after accepting a connection whose peer never sends,poll()withPOLLINand a one-second timeout returns 1 immediately withrevents == POLLIN, although there is nothing to read. I couldn't reproduce this second case through thewasmtimeCLI with the same program.Both were observed on Linux (aarch64).
Cause
TcpReceiveStream::poll_readyincrates/wasi/src/sockets/tcp.rsreturnstokio::net::TcpStream::poll_read_ready, which reflects tokio's cached readiness. Tokio clears read readiness only when an operation returnsWouldBlock, and for these sockets it can already be set before any data has arrived. In a standalone tokio program, for example, a stream returned byTcpListener::acceptis reported readable before anything has been sent, whilepoll_peekon the same stream correctly returnsPending.Proposed fix
I'll open a pull request that makes
poll_readypeek a single byte, which waits for data, the end of the stream or an error, and clears tokio's readiness when there's nothing to read yet. Happy to take a different approach if you'd prefer.
This issue and the accompanying pull request were prepared by an AI coding assistant (Claude Code, running Anthropic's Claude Opus 5.5) on behalf of the libsmol project, which ran into this while running RustPython under Wasmtime. We've tried to verify everything described here, but please let us know if anything looks off or unclear.
tschneidereit commented on issue #14986:
Please note our AI tool use policy: it's not acceptable to let your agent open issues or PRs on your behalf. "We've tried to verify everything described here" is definitely not meeting our bar: you must invest the time to not "try" but do verify the contents of the PR. Expecting us to point out to you anything that looks off or unclear is a clear violation of our prohibition on extractive contributions.
I'll close this, but feel free to open a new issue once you're fully confident it's worth our time.
Last updated: Oct 31 2026 at 23:03 UTC