Stream: git-wasmtime

Topic: wasmtime / PR #8310 Disable traps by default in `bindgen!...


view this post on Zulip Wasmtime GitHub notifications bot (Apr 05 2024 at 21:59):

alexcrichton opened PR #8310 from alexcrichton:no-trapping-imports to bytecodealliance:main:

By default previously all return types were wrapped in wasmtime::Result<T> to enable any import to return a trap to the wasm guest. This is a fair bit of boilerplate, however, and it's easy to accidentally turn a normal error into a trap. This is additionally somewhat of a power-user method as many imports probably don't end up wanting to trap.

This commit adds a new configuration option to bindgen!: trappable_imports, and switches the default to false. The previous behavior can be recovered with trappable_imports: true.

<!--
Please make sure you include the following information:

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->

view this post on Zulip Wasmtime GitHub notifications bot (Apr 05 2024 at 21:59):

alexcrichton requested fitzgen for a review on PR #8310.

view this post on Zulip Wasmtime GitHub notifications bot (Apr 05 2024 at 21:59):

alexcrichton requested wasmtime-core-reviewers for a review on PR #8310.

view this post on Zulip Wasmtime GitHub notifications bot (Apr 05 2024 at 22:44):

github-actions[bot] commented on PR #8310:

Subscribe to Label Action

cc @peterhuene

<details>
This issue or pull request has been labeled: "wasi", "wasmtime:api"

Thus the following users have been cc'd because of the following labels:

To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.

Learn more.
</details>

view this post on Zulip Wasmtime GitHub notifications bot (Apr 08 2024 at 15:40):

fitzgen requested elliottt for a review on PR #8310.

view this post on Zulip Wasmtime GitHub notifications bot (Apr 08 2024 at 21:33):

elliottt submitted PR review:

Nice!

view this post on Zulip Wasmtime GitHub notifications bot (Apr 10 2024 at 20:21):

alexcrichton merged PR #8310.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:40):

dearfl commented on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example? Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

Host side impl in Rust with trappable-imports it's like this

impl HostExample {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        let ret: String = match ext.hello() {
            Ok(s) => s,
            Err(err) => return Ok(Err(err)),
        };
        Ok(Ok(s))
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:40):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

Host side impl in Rust with trappable-imports it's like this

impl HostExample {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        let ret: String = match ext.hello() {
            Ok(s) => s,
            Err(err) => return Ok(Err(err)),
        };
        Ok(Ok(s))
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:41):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

Host side impl in Rust with trappable-imports it's like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        let ret: String = match ext.hello() {
            Ok(s) => s,
            Err(err) => return Ok(Err(err)),
        };
        Ok(Ok(s))
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:43):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        let ret: String = match ext.hello() {
            Ok(s) => s,
            Err(err) => return Ok(Err(err)),
        };
        Ok(Ok(s))
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:45):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:46):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns a Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:46):

dearfl edited a comment on PR #8310:

Hey guys, I'm relatively new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:52):

dearfl edited a comment on PR #8310:

Hey guys, I'm fairly new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:56):

dearfl edited a comment on PR #8310:

Hey guys, I'm fairly new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        // When should I return a trap/normal result? my current understanding is if something is caused by wasmtime itself
        // (ResourceTable operation failed like here, then I should return a trap, else normal result. it my understanding correct/sane?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:56):

dearfl edited a comment on PR #8310:

Hey guys, I'm fairly new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        // When should I return a trap/normal result? my current understanding is if something is caused by wasmtime itself
        // (ResourceTable operation failed like here, then I should return a trap, else normal result. is my understanding correct/sane?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 03:57):

dearfl edited a comment on PR #8310:

Hey guys, I'm fairly new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example?

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        // When should I return a trap/normal result? My current understanding is if something is
        // caused by wasmtime itself (like ResourceTable operation failed here), then I should
        // return a trap, else normal result. Is my understanding correct/sane?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 06:17):

dearfl edited a comment on PR #8310:

Hey guys, I'm fairly new to wasm/wasmtime/wasi, can you provide some per function trappable_imports example? [Nevermind, I found some example in this PR.]

Also I'd like to ask how should one handle errors in a Host impl?

Suppose I have some wit definition like this:

resource example {
    hello: func() -> result<string, error-type>,
}

The host side impl in Rust with trappable-imports is something like this

impl HostExample for ExampleContext {
    fn hello(&mut self, self_: Resource<Example>) -> wasmtime::Result<Result<String, ErrorType>> {
        // should I return a trap when resource table operations failed in here like this?
        // When should I return a trap/normal result? My current understanding is if something is
        // caused by wasmtime itself (like ResourceTable operation failed here), then I should
        // return a trap, else normal result. Is my understanding correct/sane?
        let ext: &mut Example = self.table.get_mut(&self_)?;
        // let say Example::hello returns Result<String, ErrorType>
        Ok(ext.hello())
    }

    fn drop(&mut self, self_: Resource<Example>) -> wasmtime::Result<()> {
        // same here
        self.table.delete(self_)?;
        Ok(())
    }
}

view this post on Zulip Wasmtime GitHub notifications bot (Jun 03 2024 at 15:10):

alexcrichton commented on PR #8310:

Looks like you might have already found your answer @dearfl but I can try to fill in any possible gaps and/or confirm:

In any case the code you have gisted above looks reasonable to me!

view this post on Zulip Wasmtime GitHub notifications bot (Jun 04 2024 at 01:06):

dearfl commented on PR #8310:

Looks like you might have already found your answer @dearfl but I can try to fill in any possible gaps and/or confirm:

* Whether something should be a trap or a WIT-level error depends on whether the guest should be able to recover from it. Guests can't recover from traps but can recover from WIT-level errors.

* Table-related errors are best represented as traps since that indicates a bug in the host or resource limits being hit from the guest if an error is returned.

* You might be interested in the `trappable_error_type` configuration key to have a single `Result<T,E>` instead of `Result<Result<T, E>>`, but that's not required.

In any case the code you have gisted above looks reasonable to me!

Thank you for your detailed reply.


Last updated: Dec 23 2024 at 12:05 UTC