Stream: general

Topic: Behavior differences between wasmtime runtime and library


view this post on Zulip Lucas (Nov 11 2020 at 19:52):

Hi, I have a basic C program compiled with emcc which just prints a hello world. Running it through the wasmtime runtime causes absolutely no problem, but running it in Rust using wasmtime and wasmtime-wasi (0.21.0) causes the execution to return an error "Error: failed to invoke command default, Caused by: Exited with i32 exit status 0" (code here: https://hastebin.com/vimenekuzo.rust). Running a similar program but compiled from Rust works in both cases.
I digged into the runtime code and I see no major difference between the techniques I used and the techniques used in wasmtime. Has anyone any idea why this isn't working as intended?

view this post on Zulip Peter Huene (Nov 11 2020 at 19:55):

Hi Lucas. Currently a program that calls the WASI exit function will trap with a special trap that signifies an exit. Your func.call is returning an error because of the trap and it's printing the message you're seeing. For Wasmtime, we check to see if the trap is an exit trap and simply exit the process accordingly (see here: https://github.com/bytecodealliance/wasmtime/blob/c9a3f05afd45961b0b397f97c4ad79cd7a7c807d/src/commands/run.rs#L165-L172)

Standalone JIT-style runtime for WebAssembly, using Cranelift - bytecodealliance/wasmtime

view this post on Zulip Lucas (Nov 11 2020 at 20:04):

@Peter Huene seems like I missed this bit of code while researching, thanks for the help!

view this post on Zulip Peter Huene (Nov 11 2020 at 20:05):

Hope that helps! Let us know if you run into any other issues with the API.

view this post on Zulip Till Schneidereit (Nov 11 2020 at 20:54):

I wonder if it might make sense to handle this more gracefully by default when embedding Wasmtime, too. Are there scenarios where not treating a WASI exit with status 0 as successful completion would be expected to cause issues?

view this post on Zulip Peter Huene (Nov 11 2020 at 21:06):

The problem, currently, is that _start doesn't return anything, so the only way to successfully get the above func.call to return success is to have _start return without calling into WASI to exit (which I believe it won't since it'll always call proc_exit). Given the export signature, we can't translate an exit trap internally into a return value.

view this post on Zulip Peter Huene (Nov 11 2020 at 21:07):

so perhaps a new API method for invoking a WASI module specifically?

view this post on Zulip Peter Huene (Nov 11 2020 at 21:13):

i.e. one which would handle the check for an exit trap and translate it to the exit status.

view this post on Zulip Peter Huene (Nov 11 2020 at 21:18):

Erm misread the _start code; it should return provided the original main returns zero (but obviously it won't if the program calls proc_exit itself).

view this post on Zulip Peter Huene (Nov 11 2020 at 21:27):

we could simply translate an exit trap with status 0 to Ok(_) for the invocation of _start (with a known signature) such that it won't return an error otherwise users have to check the trap for the exit code. that would make it slightly more ergonomic although it feels brittle to me.

view this post on Zulip Peter Huene (Nov 11 2020 at 21:34):

At any rate, to answer your question (finally), I don't see a problem with doing such a translation, other than the brittleness (i.e. "is the function a known WASI entry point? If so, ignore exit traps with status 0 and return Ok")

view this post on Zulip Peter Huene (Nov 11 2020 at 21:43):

This reminds me, I need to update the .NET API to allow for getting the exit status from the trap.

view this post on Zulip Till Schneidereit (Nov 11 2020 at 23:08):

Is there a real risk of misinterpreting something unrelated as a WASI exit trap with status 0 and that other thing being an error that we should surface?

view this post on Zulip Peter Huene (Nov 11 2020 at 23:42):

i don't think we'd mask any errors by handling an exit trap with status 0, since by convention it isn't an error condition. As Trap::i32_exit is public, any host function, not just proc_exit, may potentially exit trap. still, the more I think about this, the more I'm inclined to say we would ideally have something in the API that differentiates between invoking a "default" function (like what we have here) and "running a program that exits and treat non-zero as error"

view this post on Zulip Till Schneidereit (Nov 12 2020 at 18:17):

hmm, yeah, I see the value in that. At the same time I'm also slightly concerned by the potential for confusion. Will all consumers of the API always know which is the right function to use?

view this post on Zulip Peter Huene (Nov 12 2020 at 19:12):

i think we can make the distinction pretty clear; perhaps rather than something on Func for a different way to call the function, something on Linker for "invoking the default function of a module" that will both ensure the signature of the default function accepts no arguments (for now) and returns no values and does the exit trap translation for an exit status

view this post on Zulip Peter Huene (Nov 12 2020 at 19:15):

said function could even return Result<i32> and never fails with an exit trap, perhaps (caller can then just see if the command succeeded by comparing the successful result to 0?). sort of like how you would waitpid

view this post on Zulip Till Schneidereit (Nov 13 2020 at 13:35):

interesting yeah, that seems reasonable, though I don't feel like I actually understand things in this area well enough to say for sure. And it seems like this starts getting into the space of different types of modules, similar to the distinction between Commands and Reactors. Might it make sense to file an issue describing this, and getting feedback?

view this post on Zulip Andrew Brown (Dec 08 2020 at 21:37):

I just ran into pretty much the same issue described here (see https://bytecodealliance.zulipchat.com/#narrow/stream/217126-wasmtime) and, even though I had read the code @Peter Huene highlighted above (https://github.com/bytecodealliance/wasmtime/blob/c9a3f05afd45961b0b397f97c4ad79cd7a7c807d/src/commands/run.rs#L165-L172) I still forgot to check for exit traps. I would vote for adding something, to the linker perhaps, to help out with this and then document this pattern.

Standalone JIT-style runtime for WebAssembly, using Cranelift - bytecodealliance/wasmtime

view this post on Zulip Andrew Brown (Dec 08 2020 at 21:38):

I think the Wasmtime book currently tells us to use linker.get_default("")?.get0::<()>()?()?; (https://docs.wasmtime.dev/examples-rust-wasi.html) but I think that will run into the issue we're talking about here.


Last updated: Dec 23 2024 at 13:07 UTC