Stream: git-wasmtime

Topic: wasmtime / issue #14986 wasi-sockets: TCP input stream re...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 25 2026 at 15:19):

libsmol opened issue #14986:

Summary

On WASIp2, a TCP input-stream can report itself ready before the peer has sent anything: subscribe().ready() returns true right 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's poll() reports an idle socket as readable.

Reproduction

  1. With the setup helper from crates/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 both p2::sync::p2_tcp_streams and p2::async_::p2_tcp_streams. The accompanying pull request adds it as a test.

  2. Through wasi-libc, in an embedder that uses wasmtime_wasi::p2::add_to_linker_sync with Wasmtime 50.0.0: after accepting a connection whose peer never sends, poll() with POLLIN and a one-second timeout returns 1 immediately with revents == POLLIN, although there is nothing to read. I couldn't reproduce this second case through the wasmtime CLI with the same program.

Both were observed on Linux (aarch64).

Cause

TcpReceiveStream::poll_ready in crates/wasi/src/sockets/tcp.rs returns tokio::net::TcpStream::poll_read_ready, which reflects tokio's cached readiness. Tokio clears read readiness only when an operation returns WouldBlock, and for these sockets it can already be set before any data has arrived. In a standalone tokio program, for example, a stream returned by TcpListener::accept is reported readable before anything has been sent, while poll_peek on the same stream correctly returns Pending.

Proposed fix

I'll open a pull request that makes poll_ready peek 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.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 25 2026 at 15:30):

tschneidereit closed issue #14986:

Summary

On WASIp2, a TCP input-stream can report itself ready before the peer has sent anything: subscribe().ready() returns true right 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's poll() reports an idle socket as readable.

Reproduction

  1. With the setup helper from crates/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 both p2::sync::p2_tcp_streams and p2::async_::p2_tcp_streams. The accompanying pull request adds it as a test.

  2. Through wasi-libc, in an embedder that uses wasmtime_wasi::p2::add_to_linker_sync with Wasmtime 50.0.0: after accepting a connection whose peer never sends, poll() with POLLIN and a one-second timeout returns 1 immediately with revents == POLLIN, although there is nothing to read. I couldn't reproduce this second case through the wasmtime CLI with the same program.

Both were observed on Linux (aarch64).

Cause

TcpReceiveStream::poll_ready in crates/wasi/src/sockets/tcp.rs returns tokio::net::TcpStream::poll_read_ready, which reflects tokio's cached readiness. Tokio clears read readiness only when an operation returns WouldBlock, and for these sockets it can already be set before any data has arrived. In a standalone tokio program, for example, a stream returned by TcpListener::accept is reported readable before anything has been sent, while poll_peek on the same stream correctly returns Pending.

Proposed fix

I'll open a pull request that makes poll_ready peek 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.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 25 2026 at 15:30):

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