I have the following Rust code:
use wasmer::{
imports, AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, MemoryType,
Module, Store,
};
const WAT_CODE: &str = r#"
(module
(import "env" "memory" (memory 1))
(import "env" "log" (func $log (param i32 i32)))
(data (i32.const 0) "Hello, World!")
(func (export "printHello")
(call $log (i32.const 0) (i32.const 13))
)
)
"#;
pub fn main() -> anyhow::Result<()> {
let mut store = Store::default();
let module = Module::new(&store, WAT_CODE.bytes().collect::<Vec<_>>())?;
let memory = Memory::new(&mut store, MemoryType::new(1, None, false))?;
let env = FunctionEnv::new(&mut store, ());
let memory_ref = memory.clone();
let log_fn = Function::new_typed_with_env(
&mut store,
&env,
move |env: FunctionEnvMut<()>, offset: i32, length: i32| {
let mut data = vec![0; length as usize];
memory_ref
.view(&env.as_store_ref())
.read(offset as u64, &mut data)
.unwrap();
println!("Log: {:?}", String::from_utf8(data).unwrap());
},
);
let import_object = imports! {
"env" => {
"memory" => memory,
"log" => log_fn,
}
};
let instance = Instance::new(&mut store, &module, &import_object)?;
let print_hello = instance.exports.get_function("printHello")?;
print_hello.call(&mut store, &[])?;
Ok(())
}
I want to subsitute the WAT code with a wasm module that is generated from Rust code. I have created a workspace with two packages runner-code
and wasm-target-code
.
In runner-code/src/main.rs
:
use std::fs;
use wasmer::{imports, Instance, Memory, MemoryType, Module, Store, Value};
const WASM_BIN_FILE_PATH: &str = "target/wasm32-unknown-unknown/debug/wasm_target_code.wasm";
pub fn main() -> anyhow::Result<()> {
let wasm_bin = fs::read(WASM_BIN_FILE_PATH)?;
let mut store = Store::default();
let module = Module::from_binary(&store, &wasm_bin)?;
let memory = Memory::new(&mut store, MemoryType::new(1, None, false))?;
let import_object = imports! {
"env" => {
"memory" => memory.clone(),
}
};
let instance = Instance::new(&mut store, &module, &import_object)?;
let print_hello = instance.exports.get_function("store_string")?;
let Value::I32(offset) = (*print_hello.call(&mut store, &[])?)[0] else {
panic!("store_string function did not return an i32 value");
};
let mut data = vec![0; 8];
memory.view(&store).read(offset as u64, &mut data).unwrap();
println!("Log: {:?}", String::from_utf8(data).unwrap());
Ok(())
}
In wasm-target-code/src/lib.rs
:
extern "C" {
static mut IMPORTED_MEMORY: [u8; 65536];
}
fn store_string_in_imported_memory(s: &str) -> *mut u8 {
unsafe {
let ptr = IMPORTED_MEMORY.as_mut_ptr();
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0); // Null-terminate the string
ptr
}
}
#[no_mangle]
pub extern "C" fn store_string() -> *mut u8 {
store_string_in_imported_memory("John Doe")
}
Running cargo run
after building wasm-target-code
, the application fails with the error:
Error: RuntimeError: unreachable
at std::panicking::rust_panic_with_hook::h6731baa78621a747 (wasm_target_code.wasm[39]:0x3073)
at std::panicking::begin_panic_handler::{{closure}}::hb6cd8464ed39ae71 (wasm_target_code.wasm[29]:0x27f6)
at std::sys_common::backtrace::__rust_end_short_backtrace::hbdf3ddeb21a1e747 (wasm_target_code.wasm[28]:0x2726)
at rust_begin_unwind (wasm_target_code.wasm[34]:0x2d0d)
at core::panicking::panic_nounwind_fmt::h6dbc36adcb815595 (wasm_target_code.wasm[54]:0x356b)
at core::panicking::panic_nounwind::h16e38f5a9ff4ae2c (wasm_target_code.wasm[55]:0x35bf)
at core::intrinsics::copy::precondition_check::hbeb9467e311fa9db (wasm_target_code.wasm[4]:0x4b7)
at wasm_target_code::store_string_in_imported_memory::hc16b6d1a9cf40acc (wasm_target_code.wasm[0]:0x1c7)
at store_string (wasm_target_code.wasm[1]:0x268)
How can I use imported memory in Rust code targeting wasm32-unknown-unknown
?