Stream: git-wasmtime

Topic: wasmtime / issue #10088 Async exported func cancel safety?


view this post on Zulip Wasmtime GitHub notifications bot (Jan 23 2025 at 03:32):

SupernaviX opened issue #10088:

Hello!

I'm contributing to a project which calls async wasmtime exports. Sometimes, those exported functions start failing with the error "wasm trap: cannot enter component instance". I think the issue might be that the generated wasm client isn't cancel-safe.

Here's the relevant snippet from the generated code (generated by wit-bindgen 0.38):

            let _enter = span.enter();
            let callee = unsafe {
                wasmtime::component::TypedFunc::<(u32, &Event,),(Result<Response,HandleError>,)>::new_unchecked(self.handle)
            };
            let(ret0,) = callee.call_async(store.as_context_mut(),(arg0,arg1,)).await?;
            callee.post_return_async(store.as_context_mut()).await?;
            Ok(ret0)

The docs say that if you call TypedFunc's call_async method, you must call post_return_async. If this snippet is cancelled _during_ that call to call_async. then it looks like post_return_async will never be called (and there doesn't seem to be a way to recover from that).

Am I right that this code isn't cancel-safe? And if so, is there any way to recover from the cancellation?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 23 2025 at 04:07):

alexcrichton commented on issue #10088:

Thanks for the report! Even setting aside components it's pretty unlikely that any core wasm module is cancel-safe in terms of dropping a call_async future. Destructors are not run with wasm on the stack meaning that any state in the wasm module is leaked including the stack pointer itself. Given that what the component model is doing here is codifying what you probably want anyway which is to throw away the component entirely whenever an async call is cancelled. Otherwise you have no way of knowing robustly what was on the wasm stack and what was cancelled on the wasm side.

That's a bit of a winded way of saying that this is expected behavior. It's not intended to be recoverable once you drop a call_async future. The "cancel safe" part is that you're deterministically prevented from reentering the wasm module. Currently there's no way to opt-in to "yes ok but I really know the wasm is cancel-safe" and if that's what you're looking for here I think it'd be ok to add that to the API.


Last updated: Jan 24 2025 at 00:11 UTC