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

WASM_STANDALONE: Errno 63 (Out of stream resources) at fopen call #17167

Open
jfoe98 opened this issue Jun 7, 2022 · 15 comments
Open

WASM_STANDALONE: Errno 63 (Out of stream resources) at fopen call #17167

jfoe98 opened this issue Jun 7, 2022 · 15 comments

Comments

@jfoe98
Copy link

jfoe98 commented Jun 7, 2022

Error description:
I'm trying to build a standalone WASM module which is reading from a file by using WASI.
The compilation is done by running the following command:

emcc filetest.c -o filetest.wasm --no-entry -s ERROR_ON_UNDEFINED_SYMBOLS=0

The compilation works fine and succeeds without an error.

I'm using wasmtime in order to run the module:

wasmtime filetest.wasm --dir . --invoke filetest

In my working directory, there is a file 'test.txt', which only contains one line with the content "test".
Running the WASM module by using the previously mentioned command, I'm getting the following output:

Fopen failed, errno = 63

Looking up the meaning of errno 63, there seems to be an issue with stream resources:

ENOSR 63 Out of streams resources

I also activated the wasmtime WASI trace logging by setting the environment variable RUST_LOG to wasi_common=trace. Running the wasmtime command now prints the following output:

 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > wiggle abi; module="wasi_snapshot_preview1" function="fd_write"
 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > fd=Fd(1) iovs=*guest 0x500e40/2 
Fopen failed, errno = 63 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > result=Ok(24) 
 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > wiggle abi; module="wasi_snapshot_preview1" function="proc_exit"
 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > rval=1 
 TRACE wasi_common::snapshots::preview_1::wasi_snapshot_preview1 > result=I32Exit(1) 

This log shows that no open- or read-call was performed. There is only a fd_write-call, that prints the error message to the stdout file descriptor.

What is the reason behind this error and what can I do in order to get my example running?

Example code:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <emscripten/emscripten.h>

EMSCRIPTEN_KEEPALIVE void filetest() {
    FILE *handle = fopen("test.txt", "r");

    if (handle == NULL) {
         printf("Fopen failed, errno = %d", errno);
         exit(EXIT_FAILURE);
    }

    fclose(handle);
}

Version of emscripten/emsdk:
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.13 (5312576)
clang version 15.0.0 (https://github.com/llvm/llvm-project 5c6ed60c517c47b25b6b25d8ac3666d0e746b0c3)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /emsdk/upstream/bin

@sbc100
Copy link
Collaborator

sbc100 commented Jun 7, 2022

Please bear in mind that the WASI standalone support for emscripten is fairly limited. I was looking at extending it but that worked stalled: #12704

In this case it looks like the __syscall_openat function doesn't currently support opening files using fd_open:

__attribute__((__weak__))
int __syscall_openat(int dirfd, intptr_t path, int flags, ...) {
if (!strcmp((const char*)path, "/dev/stdin")) {
return STDIN_FILENO;
}
if (!strcmp((const char*)path, "/dev/stdout")) {
return STDOUT_FILENO;
}
if (!strcmp((const char*)path, "/dev/stderr")) {
return STDERR_FILENO;
}
return -EPERM;
}

@jfoe98
Copy link
Author

jfoe98 commented Jun 8, 2022

Hi @sbc100,

Thank you for your response.

I already looked into this code snipped before, because it was linked in another issue. I was wondering why I was getting another error code and as a conclusion, I assumed that in my case, this code path is not getting executed. In some other resources I read that Emscripten uses WASI whenever possible and I assumed that opening a file would be possible.

Is there any other way to open, read and write files with Emscripten or do I need to switch to WASI SDK?

@sbc100
Copy link
Collaborator

sbc100 commented Jun 8, 2022

Yes, when you build without -sSTANDALONE_WASM emscripten implements __syscall_openat in JavaScript and has it own filesystem implemented there.

However, those binaries won't run on wasmtime since wasmtime doesn't support the emscripten syscalls.

@sbc100
Copy link
Collaborator

sbc100 commented Jun 8, 2022

(BTW, you are implicitly asking for -sSTANDALONE_WASM by outputing a wasm file directly). If you build with -o filetest.js then you can run that resulting code under node or in the browsers.

@jfoe98
Copy link
Author

jfoe98 commented Jun 8, 2022

Hi @sbc100,

I‘m currently working on a research paper with the goal to find out which source languages and compilers are the most suitable ones for targeting server side workloads in standalone WASM runtimes like wasmtime. So for me, it is not an option to switch to browsers or node.
I already implemented various workloads in some different source languages and my emscripten-based implementations are working fine so far. Currently, I‘m implementing an i/o intensive workload in order to compare how WASI syscalls are used. Regarding emscripten, my current understanding is that i/o operations (execpt the default file descriptors STDIN, STDOUT, STDERR) are not possible as of now.

Thank you for your help so far!

@sbc100
Copy link
Collaborator

sbc100 commented Jun 8, 2022

If you are only targeting the server then emscripten is likely not the right choice for you. Have you looked at wasi-sdk (https://github.com/WebAssembly/wasi-sdk)?

@jfoe98
Copy link
Author

jfoe98 commented Jun 9, 2022

Hi @sbc100,

I have included WASI-SDK in my evaluation. Works fine!

@turbolent
Copy link

@sbc100 I just ran into this limitation too. I read about FS in the documentation, and also ensured it is initialized in the browser, and kept on wondering why the read for the /dev/urandom default device would fail, even though it exits in the FS ...

Would it be possible to have __syscall_openat just call the WASI open function? (which is basically openat)

@sbc100
Copy link
Collaborator

sbc100 commented Jul 5, 2022

@turbolent the easiest solution would be to stop building with STANDALONE_WASM. Do you need that option for some reason.

The long term solution is to land #12704

@turbolent
Copy link

Yes, I use STANDALONE_WASM to produce a binary with minimal imports, ideally just WASI. I'm working on https://github.com/turbolent/w2c2, i.e. I'm trying to port applications and compile them to C. It has WASI support, so I'd like to use that. Emscripten seems to provide much better support than e.g. wasi-sdk.

#12704 look good. Is there any reason why it hasn't landed yet? I could help improve WASI support if that's something you'd be happy to accept.

Maybe w2c2 could add support or the Emscripten imports, though there seem to be a lot. How stable is that interface, and is there any documentation for it?

@sbc100
Copy link
Collaborator

sbc100 commented Jul 10, 2022

Even if #12704 lands, only the most simple program will contain just wasi imports/exports. Anymore more complex that you could build with wasi-sdk likely contain emscripten-specific imports, so you will be forces to implement some parts of emscripten.

The emscripten ABI is relatively stable, but not set in stone and not well documented. Its more of an implementation detail.

@turbolent
Copy link

@sbc100 Where can I find the ABI and related documentation? Do you think it is worth it to implement it natively, or would an attempt like that rather futile based on how often it changes?

@sbc100
Copy link
Collaborator

sbc100 commented Aug 30, 2022

The emscripten API between JS and wasm is not fully documented anywhere (at least not that I know of). There is some information here: https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone. And a blog post here: https://v8.dev/blog/emscripten-standalone-wasm.

We do (mostly) treat this API as more of an implementation detail. However, we are aware that folks like you would like to target it, and I have been trying to simplify it over time to make the job easier. I would not say it a futile effort to track it, but be prepared for occasional changes.

@turbolent
Copy link

@sbc100 I saw that #12704 finally landed, nice!

As for the empscripten API between JS and WASM: Has there been any further advanced in stabilizing it? How much did it change over the last year? It would be great to better understand what "occasional changes" to expect, to not make this a futile effort (it's just a side project for me).

Also: Do you know of any other implementations of that API apart from the reference JS implementation in this repo?

@sbc100
Copy link
Collaborator

sbc100 commented Oct 16, 2023

I don't know of any other implementations of the emscripten JS API, but I wouldn't be surprised if there was some partial implementation out there.

In terms of stability I'm not sure how to quickly come up with an answer for that. I think the __syscall APIs are very stable and haven't changed in several years, but other APIs can and do change from time to time. There are maybe different JS APIs in emscripten (see src/library_*.js). Do you have some you are particularly interested in stabilizing/implementing? A lot of them, for example, related to graphics and sounds (e.g. opengl) and I assuming you are not interesting in those one? Do you know what type of applications you want to run?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants