I'm playing around with the Rust wasmtime API, and I'm trying to pass a pointer to a struct defined in a crate that both the runtime crate and the compiled wasm depend on when I compile the wasm crate to wasm32-wasi, the pointer becomes a u32 parameter, but I'm not sure what to do in the caller to pass a pointer that can be used properly. I tried copying the struct value into the exported memory and passing the address to that, but that still resulted in an out of bounds trap being thrown.
Copying the struct into exported memory is right move, did compiled wasm allocated memory for this structure or you just selected the offset randomly?
I just started at 0, the crate that I'm trying to run
is very minimal. Here's the code https://hasteb.in/jufodijo.swift
@Kaitlyn Kenwell 0 is not right. Ask wasm to allocate memory for you, e.g. Vec::with_capacity + mem::forget perhaps
I don't understand how that ties in to sending a struct from the host into the wasm application
Based on your example your structure contains other pointers: the s
@Kaitlyn Kenwell Do you set 5 i32's in the wasm exported memory for the CommonStruct
? Which values are these initialized to?
if buffer of the String
points to some weird location, you might be getting out of bounds.
https://hasteb.in/inarumol.js here's what I have in the host, ignore the &str parameter, I cut that out to make sure that extra pointers weren't a factor
I think main issue here is that you are mixing wasm pointer and native pointer, e.g. let ptr = &buf[0] as *const _ as i32;
it shall be let ptr = 0;
-- you cannot cast 64 bit pointer to i32, it needs to be offset in wasm memory (from host point of view)
ok
also std::ptr::copy
definitely wrong, since it copied all pointers as is (not i32 offsets as mentioned above)
for what its worth: this sort of translation between guest memory and host is complicated and easy to get wrong in ways that may cause security problems (e.g. letting the guest modify a host pointer). the crates/wiggle crate is designed for automatically generating host interfaces from .witx
descriptions. it is currently used in crates/wasi-common.
we're also using it over in lucet. unfortunately i'm not the authority on how to integrate it with wasmtime, but hopefully you can follow how its use in wasi-common works?
For more info on how to use these, @Radu M recently wrote a blog post describing how to add syscalls using wasi-common: https://radu-matei.com/blog/adding-wasi-syscall/
oh wow, i was not aware of that!
great blog post @Radu M
(deleted)
Sort of related to this, I've decided to just try passing data with marshalling and to use a proc macro to make it easier to use on the plugin end. in general, how can a host know where is a safe region in the memory to copy to? I didn't run into any problems with a fairly simple program with just copying into an early index in the memory, but when I printed it out I did see more stuff near the bottom. Not sure how I can be sure if I won't ruin anything accidentally by just choosing some arbitrary location near the start to inject values
@Kaitlyn Kenwell the general principle is that the wasm program itself owns and manages its memory -- e.g., the copy of the standard library that you link with inside the wasm environment will be keeping its own malloc data structures. So the best way to allow for a caller to pass data in would be to invoke an entry point first to ask for a block of memory, then fill that memory with your data, then invoke the main function call. E.g., export both a alloc_buffer(len: usize) -> *mut u8
function along with your test_fun(...)
In Rust, you can alloc a Vec and then forget
it, as Yury hints at above, or for a struct, you can use Box::into_raw
There is Vec::into_raw_parts
, which returns a ptr, len and capacity.
Last updated: Dec 23 2024 at 12:05 UTC