alexcrichton opened issue #10933:
Currently in Wasmtime it's safe to acquire
&mut wasmtime::runtime::vm::Instancein various locations and this is used pervasively. Technically though this alone is not sound as it allowsmem::swap-ing two instances. This would mean that the offsets, used to calculate the size of the allocation used for deallocation, could get mixed up (among other issues). Ideally we would have an abstraction which allows mutable access but disallows usage ofmem::swap. In a sense this is similar toStoreContextMutwhich basically entirely exists to preventmem::swap-ing two stores. This approach has a lot of ergonomic downsides though and it's not fun to write against.Another alternative is to assume that this basically doesn't happen (it's an internal type in Wasmtime, and it's pretty unlikely we reach for doing this naturally). That would mean we'd document on some
unsafeblock somewhere "this requires auditing the entire codebase" which practically wouldn't happen but would in-practice work alright.Another possible alternative would be something like:
struct InstanceFields { /* ... */ } // what `struct Instance` is today pub struct Instance { fields: InstanceFields, _something_forcing_mut_ref_to_be_dst: [u8], }We'd keep methods and such on
impl Instance { ... }andInstancewould itself be a dynamically sized type which would disallow overwriting the entire structure via the type system. Runtime-wise this would have a slight cost as passing it by reference passes two values and one value is always zero (the_something_forcing_mut_ref_to_be_dstwould always be zero-length, we wouldn't want it to encompass theVMContextas that would inaccurately model how&Instanceactually has mutable provenance toVMContext, but if[u8]covered the whole field then it would also seemingly be only shared provenance). LLVM might be able to figure that out though with enough inlining?Perosnally I'm tempted to pursue this last solution of a dynamically-sized type. It would still require auditing the entire
vm/instance.rsmodule (as you could still overwriteInstanceFieldsin there) but that's a much less daunting task than the entire codebase.
alexcrichton commented on issue #10933:
I'll also note that after https://github.com/bytecodealliance/wasmtime/pull/10934 this issue is equally applicable to components as well.
bjorn3 commented on issue #10933:
So basically Instance needs to be pinned?
alexcrichton commented on issue #10933:
Hm yes good point that's a much better articulation! Handing out
&mut Instancewould not be safe and we would instead have to usePin<&mut Instance>everywhere. Projection to each field would be unsafe but managable. That's probably a better idea than the DST trick I was thinking of.
alexcrichton added the wasm-proposal:component-model label to Issue #10933.
fitzgen closed issue #10933:
Currently in Wasmtime it's safe to acquire
&mut wasmtime::runtime::vm::Instancein various locations and this is used pervasively. Technically though this alone is not sound as it allowsmem::swap-ing two instances. This would mean that the offsets, used to calculate the size of the allocation used for deallocation, could get mixed up (among other issues). Ideally we would have an abstraction which allows mutable access but disallows usage ofmem::swap. In a sense this is similar toStoreContextMutwhich basically entirely exists to preventmem::swap-ing two stores. This approach has a lot of ergonomic downsides though and it's not fun to write against.Another alternative is to assume that this basically doesn't happen (it's an internal type in Wasmtime, and it's pretty unlikely we reach for doing this naturally). That would mean we'd document on some
unsafeblock somewhere "this requires auditing the entire codebase" which practically wouldn't happen but would in-practice work alright.Another possible alternative would be something like:
struct InstanceFields { /* ... */ } // what `struct Instance` is today pub struct Instance { fields: InstanceFields, _something_forcing_mut_ref_to_be_dst: [u8], }We'd keep methods and such on
impl Instance { ... }andInstancewould itself be a dynamically sized type which would disallow overwriting the entire structure via the type system. Runtime-wise this would have a slight cost as passing it by reference passes two values and one value is always zero (the_something_forcing_mut_ref_to_be_dstwould always be zero-length, we wouldn't want it to encompass theVMContextas that would inaccurately model how&Instanceactually has mutable provenance toVMContext, but if[u8]covered the whole field then it would also seemingly be only shared provenance). LLVM might be able to figure that out though with enough inlining?Perosnally I'm tempted to pursue this last solution of a dynamically-sized type. It would still require auditing the entire
vm/instance.rsmodule (as you could still overwriteInstanceFieldsin there) but that's a much less daunting task than the entire codebase.
Last updated: Dec 06 2025 at 06:05 UTC