unikraft / lib-musl

musl: A C standard library
Other
9 stars 29 forks source link

`poll` returns `ENOSYS` #58

Closed mkroening closed 1 year ago

mkroening commented 1 year ago

On Linux, when the Rust runtime initializes, Rust sanitizes the standard streams: (std/src/sys/unix/mod.rs#L54-L57)

    // The standard streams might be closed on application startup. To prevent
    // std::io::{stdin, stdout,stderr} objects from using other unrelated file
    // resources opened later, we reopen standards streams when they are closed.

Rust does so, by first polling on the file descriptors. On EINVAL, EAGAIN, and ENOMEM, Rust falls back from using poll (std/src/sys/unix/mod.rs#L108-L118).

On Unikraft, with musl, this returns ENOSYS, though, resulting in an abort.

C code for reproduction:

#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <stddef.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    if (poll(NULL, 0, 0) == -1) {
        printf("%i\n", errno == ENOSYS);
        assert(errno == EINVAL || errno == EAGAIN || errno == ENOMEM);
    }

    return 0;
}

prints

[...]
1
Assertion failed: errno == EINVAL || errno == EAGAIN || errno == ENOMEM (/home/kroening/devel/unikraft/apps/app-helloworld/main.c: main: 10)
[    0.106567] CRIT: [libmusl] <abort.c @    7> abort called

We could approach this issue from both Unikraft and Rust. We could either

  1. Make poll on Unikraft return any of EINVAL, EAGAIN, or ENOMEM or
  2. make Rust also fall back from using poll on ENOSYS.

I personally think, 2 would be the better option, though that somewhat conflicts with the idea that we should not have to adjust programs for running on Unikraft and instead fix the issue on our side.

What do you think?

mkroening commented 1 year ago

Closing this, as this is expected behavior and Rust does not want to change the behavior for Linux. We'll special case this for Unikraft in Rust.