Skip to content
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

WASI socket read returns 0 when it should return at least 1 #9938

Open
sunfishcode opened this issue Jan 6, 2025 · 3 comments
Open

WASI socket read returns 0 when it should return at least 1 #9938

sunfishcode opened this issue Jan 6, 2025 · 3 comments
Labels
bug Incorrect behavior in the current implementation that needs fixing

Comments

@sunfishcode
Copy link
Member

Test Case

Compile this Rust program with the wasm32-wasip2 target and the wasi crate as a dependency:

use wasi::sockets::network::{IpAddressFamily, IpSocketAddress, Ipv4SocketAddress};
use wasi::io::streams::StreamError;
use std::net::Ipv4Addr;

fn main() {
    let network = wasi::sockets::instance_network::instance_network();

    let family = IpAddressFamily::Ipv4;

    let socket = wasi::sockets::tcp_create_socket::create_tcp_socket(family).unwrap();
    let pollable = socket.subscribe();

    let ip = Ipv4Addr::new(127, 0, 0, 1).octets();
    let address = (ip[0], ip[1], ip[2], ip[3]);
    let port = 8080;
    let local_address = IpSocketAddress::Ipv4(Ipv4SocketAddress { port, address });

    socket.start_bind(&network, local_address).unwrap();
    pollable.block();
    socket.finish_bind().unwrap();

    socket.start_listen().unwrap();
    pollable.block();
    socket.finish_listen().unwrap();

    pollable.block();
    let (_socket, input, _output) = socket.accept().unwrap();

    let input_subscription = input.subscribe();

    loop {
        input_subscription.block();

        match input.read(4096) {
            Ok(r) => {
                // We blocked on our input before reading, so there should be
                // at least one byte ready.
                assert!(!r.is_empty(), "read after blocking should return at least one byte");
            }
            Err(StreamError::Closed) => return,
            Err(StreamError::LastOperationFailed(err)) => {
                unreachable!("error! {:?}", std::io::Error::other(err.to_debug_string()));
            }
        };
    }
}

Steps to Reproduce

Run it with wasmtime -Sinherit-network and it'll start a server listening for input on port 8080.

In another terminal, run nc localhost 8080 and type some text and press enter. This causes the server to fail the "read after blocking should return at least one byte" assert.

Expected Results

The server should not panic. read after blocking should produce at least one byte, or fail.

Actual Results

read returns 0 bytes, and trips the assert in the testcase.

Versions and Environment

I can reproduce this on Wasmtime 27.0.0 (8eefa23 2024-11-20) and on a Wasmtime built from top-of-tree today.

Operating system: Linux

Architecture: x86_64

@sunfishcode sunfishcode added the bug Incorrect behavior in the current implementation that needs fixing label Jan 6, 2025
@sunfishcode
Copy link
Member Author

The relevant line in the spec is at https://github.com/WebAssembly/wasi-io/blob/main/wit/streams.wit#L51:

The pollable given by subscribe will be ready when more bytes are available.

The specific issue here is that the pollable reports being ready when zero bytes are available.

@pchickey
Copy link
Contributor

pchickey commented Jan 7, 2025

Is this issue related? #9691

@sunfishcode
Copy link
Member Author

Yes, that looks very similar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Incorrect behavior in the current implementation that needs fixing
Projects
None yet
Development

No branches or pull requests

2 participants