-
Notifications
You must be signed in to change notification settings - Fork 266
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
Allowing host functions to return an error instead of panicing #258
Comments
This is important for porting some existing gasm code, which return a second value which is an error. We need a clean path to migrate folks and saying "panic" looks like a step backwards. |
actually I looked closer at the code and it was returning an errno (uint32) cast as an error. Let's start with #433 and also documenting what panics are used for now. We have to analyze https://github.com/WebAssembly/exception-handling before proceeding with any typed errors I think |
What is the current approach for error handling within the host function? Right now, I am running a Rust-based wasm module and if my Go host function panics, it's not something I can catch on the Rust side. What is the defacto method for communicating host function errors to the wasm module calling the host function? |
hi @clarkmcc WebAssembly doesn't have a way in 1.0 or 2.0 to catch exceptions, though it may be the case in the future. So, the way errors work are somewhat old school meanwhile. The first return val can be an errno for a recoverable function. This is how WASI works, for example. Please reply if you need more guidance! |
@codefromthecrypt Okay, can you clarify for me what I should do about my existing return value? Right now, I'm returning a "fat pointer" I guess which is a extern "C" {
pub fn get_value(ptr: u32, len: u32) -> u64;
} The host function |
I think what you'll want to look at are..
hope these breadcrumbs help! |
I don't think rust supports multiple values, so your signature might look like this. Note you probably don't need to declare a i64 for the errorno a smaller i32 is likely fine pub type Size = usize;
pub type Errno = u16;
#[link(wasm_import_module = "your_module")]
extern "C" {
fn get_value(ptr: *mut u8, len: Size) -> Errno;
} ported from wasi |
@codefromthecrypt let me clarify, in the |
@clarkmcc gotcha. here are two ideas:
does this help? |
@codefromthecrypt In the long term, I'd like to switch to flatbuffers instead of serialized JSON strings which is what I'm doing now so that I can get by bearings first. Given that, I'm guessing the null-terminated string approach is not an option. Can you clarify what your second option would look like, I'm not sure that I follow completely. Last night I took a stab at this type of process
It almost worked but there was some slight data corruption and then out-of-bounds errors when the strings were really long so I'm sure I did something wrong. Then I realized this seems like quite a bit of work for what I think is a pretty common use case (arbitrary input bytes and arbitrary output bytes). Am I overthinking this? Edit: Solved it within a few minutes this morning, it's amazing how that works. The problem was memory corruption by the wee allocator. Addresses read from Rust looked good, the same address read from Go through the guest's shared memory was corrupted between bytes 0-8. No idea what the problem actually is but switching to the default allocator seemed to solve the problem. I still would like to know if there's a better way to do this. |
@clarkmcc I think we still owe (many things including) an error handling example, as using only numbers and memory is indeed a bit lacking. The code you accumulate to pass back an error message is an example of that. Also, the allocator in rust overwrites the first bytes on dealloc iirc. I ran into this in the allocation example, which is different than tinygo which lazy collects. the lack of a coherent GC approach is basically another issue when using "grey box wasm" eg functions you collaborate with vs what's easier (main functions that only use wasm and wasi) There are some things I could suggest to move forward with next, now that you've managed something working 🥂
Either way, good luck and hope to see you around. The bruised knuckles are sadly a part of working on things right now, but we do want to help where we can. Thinking through what you asked above has helped. |
Right now, host functions that reach an abnormal end, or have to exit are required to panic out.
Ex. intentional return
Ex. abend (ex on I/O)
This is an alternative to allowing signatures that return an error, then propagating out anyway. The reasons this isn't done yet are:
I believe this is confusing from a developer point-of-view, and can result in unnecessary error wrapping. An alternative may be to retain using panics internally for global exit, but use a different call site for functions with an error signature. These functions could internally panic on error to retain the same behavior.
The text was updated successfully, but these errors were encountered: