diff --git a/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs b/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs index 235e2d874132..e87e70726824 100644 --- a/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs +++ b/crates/test-programs/wasi-tests/src/bin/poll_oneoff.rs @@ -19,6 +19,18 @@ unsafe fn poll_oneoff_impl(r#in: &[wasi::Subscription], nexpected: usize) -> Vec out } +unsafe fn test_empty_poll() { + let r#in = []; + let mut out: Vec = Vec::new(); + let error = wasi::poll_oneoff(r#in.as_ptr(), out.as_mut_ptr(), r#in.len()) + .expect_err("empty poll_oneoff should fail"); + assert_eq!( + error.raw_error(), + wasi::ERRNO_INVAL, + "error should be EINVAL" + ); +} + unsafe fn test_timeout() { let clock = wasi::SubscriptionClock { id: wasi::CLOCKID_MONOTONIC, @@ -220,6 +232,7 @@ unsafe fn test_fd_readwrite_invalid_fd() { unsafe fn test_poll_oneoff(dir_fd: wasi::Fd) { test_timeout(); + test_empty_poll(); // NB we assume that stdin/stdout/stderr are valid and open // for the duration of the test case test_stdin_read(); diff --git a/crates/wasi-common/src/hostcalls_impl/misc.rs b/crates/wasi-common/src/hostcalls_impl/misc.rs index 893d3dae0b73..f07aa727f4da 100644 --- a/crates/wasi-common/src/hostcalls_impl/misc.rs +++ b/crates/wasi-common/src/hostcalls_impl/misc.rs @@ -218,6 +218,12 @@ pub(crate) fn poll_oneoff( let mut timeout: Option = None; let mut fd_events = Vec::new(); + + // As mandated by the WASI spec: + // > If `nsubscriptions` is 0, returns `errno::inval`. + if subscriptions.is_empty() { + return Err(Error::EINVAL); + } for subscription in subscriptions { match subscription.r#type { wasi::__WASI_EVENTTYPE_CLOCK => { @@ -280,6 +286,9 @@ pub(crate) fn poll_oneoff( log::debug!("poll_oneoff timeout = {:?}", timeout); log::debug!("poll_oneoff fd_events = {:?}", fd_events); + // The underlying implementation should successfully and immediately return + // if no events have been passed. Such situation may occur if all provided + // events have been filtered out as errors in the code above. hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?; let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?;