Stream: git-wasmtime

Topic: wasmtime / issue #9579 Make the imported memory available...


view this post on Zulip Wasmtime GitHub notifications bot (Nov 07 2024 at 08:10):

Lohann opened issue #9579:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

Hello, I need to access the imported memory inside a functions, then I realized the Caller only show exports, not imports, so I had a lot of trouble to get Wasmtime store working with MaybeUnit, this simple solution segfaults:

pub struct State {
    pub memory: Memory,
}

let state = MaybeUninit::<State>::uninit();
let mut store = Store::new(engine, state);

let memory_type = MemoryType::new(16, None);
store.data_mut().memory.write(Memory::new(&mut store, memory_type)?);

let store = unsafe {
    std::mem::transmute::<Store<MaybeUninit<State>>, Store<State>>(store)
};

// segfaults below
let instance = Instance::new(&mut store, &module, &imports)?;

Then I realized the issue is that there's no way for me transmute only the State, I need to transmute the Store which is not recommended, once rust doesn't guarantee the same memory layout:

assert_eq!(size_of::<Option<bool>>(), 1);
assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);

Actually I haven't find any way to use MaybeUnit that doesn't look hacky, and I want to avoid the usage of Option and unwraps in the code, once it bloats the binary with panic data.

Alternatives

  1. Make the imported memory easily available inside Functions, ex: expose it in the Caller.
  2. Use #[repr(C)] on Store, so we can safely transmute it.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 07 2024 at 08:12):

Lohann edited issue #9579:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

Hello, I need to access the imported memory inside a functions, then I realized the Caller only show exports, not imports, so I had a lot of trouble to get Wasmtime store working with MaybeUnit, this simple solution segfaults:

pub struct State {
    pub memory: Memory,
}

let state = MaybeUninit::<State>::uninit();
let mut store = Store::new(engine, state);

let memory_type = MemoryType::new(16, None);
store.data_mut().memory.write(Memory::new(&mut store, memory_type)?);

let store = unsafe {
    std::mem::transmute::<Store<MaybeUninit<State>>, Store<State>>(store)
};

// ...
let imports = [memory.into()];

// segfaults below
let instance = Instance::new(&mut store, &module, &imports)?;

Then I realized the issue is that there's no way for me transmute only the State, I need to transmute the Store which is not recommended, once rust doesn't guarantee the same memory layout:

assert_eq!(size_of::<Option<bool>>(), 1);
assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);

Actually I haven't find any way to use MaybeUnit that doesn't look hacky, and I want to avoid the usage of Option and unwraps in the code, once it bloats the binary with panic data.

Alternatives

  1. Make the imported memory easily available inside Functions, ex: expose it in the Caller.
  2. Use #[repr(C)] on Store, so we can safely transmute it.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 07 2024 at 15:47):

alexcrichton commented on issue #9579:

Where possible I'd recommend avoiding unsafe. If things are segfaulting it's probably due to that, so for example you could store Option<Memory> instead of using MaybeUninit and then there's no need for transmute and this probably won't segfault.

Otherwise though is there a problem with storing the memory in State?

view this post on Zulip Wasmtime GitHub notifications bot (Nov 10 2024 at 23:33):

Lohann commented on issue #9579:

Otherwise though is there a problem with storing the memory in State?

There's no problem, is just there's no examples of that, and is not ergonomic as using exported memory, rust encourages the use of Typestate Pattern, where the state of an object guarantees it is valid. In this case I want to guarantee the memory ALWAYS exists, that's why I don't want to use Option.
One example is the NonZeroU32 by knowing the number is never zero, the rust compiler can do some neat optimizations:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6778305b1980ec60413183a0a1127a4d

assert_eq!(size_of::<u32>(), 4);
assert_eq!(size_of::<Option<u32>>(), 8);
assert_eq!(size_of::<Option<NonZeroU32>>(), 4);

In my case I want to guarantee the memory always exists, I don't want to handle the Option::None everywhere, neither use unwrap() everywhere, that's ok if there's no other option, but I think this is something that should be supported somehow by wasmtime, once the Store owns the memory, makes sense I be able to store it together with the store.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 10 2024 at 23:41):

Lohann edited a comment on issue #9579:

Otherwise though is there a problem with storing the memory in State?

There's no problem, but rust encourages the use of Typestate Pattern, where the state of an object guarantees it is valid. In this case I want to guarantee the memory ALWAYS exists, that's why I don't want to use Option.
One example is the NonZeroU32 by knowing the number is never zero, the rust compiler can do some neat optimizations:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6778305b1980ec60413183a0a1127a4d

assert_eq!(size_of::<u32>(), 4);
assert_eq!(size_of::<Option<u32>>(), 8);
assert_eq!(size_of::<Option<NonZeroU32>>(), 4);

In my case I want to guarantee the memory always exists, I don't want to handle the Option::None everywhere, neither use unwrap() everywhere, that's ok if there's no other option, but I think this is something that should be supported somehow by wasmtime, once the Store owns the memory, makes sense I be able to store it together with the store.

view this post on Zulip Wasmtime GitHub notifications bot (Nov 12 2024 at 04:37):

alexcrichton commented on issue #9579:

One thing you could perhaps do is to create a dummy Memory with a throwaway Store which is placed within future Stores as they're created. That would then be overwritten to the "real" memory once the store is created. That way you can store just Memory without having to deal with Option and you won't have to deal with any unsafety either.


Last updated: Dec 23 2024 at 12:05 UTC