Return EINVAL in poll_oneoff with no events. (#838)

* Return EINVAL in poll_oneoff with no events.

We adhere to WebAssembly/WASI#193.

* Add a test for empty poll.
This commit is contained in:
Marcin Mielniczuk
2020-01-17 22:41:37 +01:00
committed by Dan Gohman
parent 448faed5ca
commit 815576edc5
2 changed files with 22 additions and 0 deletions

View File

@@ -19,6 +19,18 @@ unsafe fn poll_oneoff_impl(r#in: &[wasi::Subscription], nexpected: usize) -> Vec
out out
} }
unsafe fn test_empty_poll() {
let r#in = [];
let mut out: Vec<wasi::Event> = 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() { unsafe fn test_timeout() {
let clock = wasi::SubscriptionClock { let clock = wasi::SubscriptionClock {
id: wasi::CLOCKID_MONOTONIC, id: wasi::CLOCKID_MONOTONIC,
@@ -220,6 +232,7 @@ unsafe fn test_fd_readwrite_invalid_fd() {
unsafe fn test_poll_oneoff(dir_fd: wasi::Fd) { unsafe fn test_poll_oneoff(dir_fd: wasi::Fd) {
test_timeout(); test_timeout();
test_empty_poll();
// NB we assume that stdin/stdout/stderr are valid and open // NB we assume that stdin/stdout/stderr are valid and open
// for the duration of the test case // for the duration of the test case
test_stdin_read(); test_stdin_read();

View File

@@ -218,6 +218,12 @@ pub(crate) fn poll_oneoff(
let mut timeout: Option<ClockEventData> = None; let mut timeout: Option<ClockEventData> = None;
let mut fd_events = Vec::new(); 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 { for subscription in subscriptions {
match subscription.r#type { match subscription.r#type {
wasi::__WASI_EVENTTYPE_CLOCK => { wasi::__WASI_EVENTTYPE_CLOCK => {
@@ -280,6 +286,9 @@ pub(crate) fn poll_oneoff(
log::debug!("poll_oneoff timeout = {:?}", timeout); log::debug!("poll_oneoff timeout = {:?}", timeout);
log::debug!("poll_oneoff fd_events = {:?}", fd_events); 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)?; hostcalls_impl::poll_oneoff(timeout, fd_events, &mut events)?;
let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?; let events_count = u32::try_from(events.len()).map_err(|_| Error::EOVERFLOW)?;