I have a WASM module as follows
#[no_mangle]
pub extern "C" fn process_bytes(ptr: *const u8, len: usize) -> u8 {
if len > 0 {
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
let first = bytes[0];
first
} else {
0
}
}
It accepts a byte array, returning the first byte.
This module is compiled with cargo build --target wasm32-unknown-unknown --release
then called from another crate that uses wasmer
pub mod get_tx_data;
use wasmer::{imports, Cranelift, Instance, Module, Store, Value};
fn main() {
// Read the Wasm file
let wasm_bytes = include_bytes!("banana_swap.wasm");
// Create a store
let mut store = Store::default();
// let compiler = Cranelift::default();
// let mut store = Store::new(compiler);
// Compile the module
let module = Module::new(&store, wasm_bytes).unwrap();
// Create an import object with the host function
let import_object = imports! {};
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let function = instance.exports.get_function("process_bytes").unwrap();
// Example byte array
let byte_array: Vec<u8> = vec![0x48, 0x65, 0x6C, 0x6C, 0x6F];
// Call the exported function with the byte array
let result = function.call(&mut store, &[
Value::I32(byte_array.as_ptr() as i32),
Value::I32(byte_array.len() as i32)
]).unwrap();
// Check the result
println!("Result: {:?}", result);
}
This gives error signal_trap: Some(HeapAccessOutOfBounds) }
. The array length is being read properly, I'm able to return it from the function. What went wrong?
thread 'main' panicked at indexer-core/src/main.rs:31:8:
called `Result::unwrap()` on an `Err` value: RuntimeError { source: Wasm { pc: 127833057173522, backtrace: 0: <unknown>
1: <unknown>
2: <unknown>
3: <unknown>
4: <unknown>
5: <unknown>
6: <unknown>
, signal_trap: Some(HeapAccessOutOfBounds) }, wasm_trace: [FrameInfo { module_name: "<module>", func_index: 0, function_name: Some("process_bytes"), func_start: SourceLoc(119), instr: SourceLoc(137) }] }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
https://github.com/icedancer-io/indexer-core/tree/stackoverflow
Use the stackoverflow branch. How to run-
cd banana-swap && cargo build --target wasm32-unknown-unknown --release && cd .. && cp ./target/wasm32-unknown-unknown/release/banana_swap.wasm indexer-core/src/banana_swap.wasm && cargo run --bin indexer-core
WASM cannot access regions outside of its allocated memory (of the host). That would defeat the entire point of sandboxing using WASM.
You need to copy the data into WASM memory, then pass the address from there.
use wasmer::{imports, Instance, Module, Store, Value};
fn main() {
// Read the Wasm file
let wasm_bytes = include_bytes!("../../target/wasm32-unknown-unknown/release/guest.wasm");
// Create a store
let mut store = Store::default();
// let compiler = Cranelift::default();
// let mut store = Store::new(compiler);
// Compile the module
let module = Module::new(&store, wasm_bytes).unwrap();
// Create an import object with the host function
let import_object = imports! {};
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
let function = instance.exports.get_function("process_bytes").unwrap();
// Example byte array
let byte_array: Vec<u8> = vec![0x48, 0x65, 0x6C, 0x6C, 0x6F];
let memory = instance.exports.get_memory("memory").unwrap();
let view = memory.view(&store);
// Cannot be 0 because null is disallowed in Rust references.
view.write(1, &byte_array).unwrap();
// Call the exported function with the byte array
let result = function
.call(
&mut store,
&[Value::I32(1), Value::I32(byte_array.len() as i32)],
)
.unwrap();
// Check the result
println!("Result: {:?}", result);
}
If you don't know a free place in the memory, you can for example ask the guest to allocate X bytes using its allocator and return their address, then write there.