Skip to content
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

Make the imported memory available in functions #9579

Open
Lohann opened this issue Nov 7, 2024 · 3 comments
Open

Make the imported memory available in functions #9579

Lohann opened this issue Nov 7, 2024 · 3 comments

Comments

@Lohann
Copy link

Lohann commented Nov 7, 2024

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.
@alexcrichton
Copy link
Member

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?

@Lohann
Copy link
Author

Lohann commented Nov 10, 2024

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.

@alexcrichton
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants