Skip to content

Instantly share code, notes, and snippets.

@Denys-Bushulyak
Last active March 10, 2023 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Denys-Bushulyak/2531f297a85d048e17b8a067262f13b1 to your computer and use it in GitHub Desktop.
Save Denys-Bushulyak/2531f297a85d048e17b8a067262f13b1 to your computer and use it in GitHub Desktop.
This gist show examples how to use webassembly memory
use std::ffi::CString;
use std::mem::forget;
use wasmtime::{Instance, Module, Store};
//
// Code of module which have to be compiled to wasm library
//
// use std::alloc::{alloc, Layout};
// use std::ffi::CString;
// use std::mem::forget;
//
// #[no_mangle]
// pub fn allocate_memory(size: usize) -> *mut u8 {
// let align = std::mem::align_of::<usize>();
// let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
// unsafe { alloc(layout) }
// }
//
// #[no_mangle]
// pub fn add_end(ptr: *const u8) -> usize {
// let text = unsafe { CString::from_raw(ptr as *mut _) };
// let mut text = text.into_bytes();
// text.extend(b" (FIN)\0");
//
// let length = text.len();
//
// forget(text);
//
// length
// }
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut store: Store<()> = Store::default();
let module = Module::from_file(
store.engine(),
"./target/wasm32-unknown-unknown/debug/app.wasm",
)?;
let instance = Instance::new(&mut store, &module, &[])?;
let alloc = instance.get_typed_func::<i32, i32>(&mut store, "allocate_memory")?;
let hello_text = CString::new("Hello, dear world!")?;
let len = hello_text.as_bytes_with_nul().len() as i32;
// module_module_memory_ptr is a pointer to the memory allocated by the module.
// It is relative to the module's memory.
let allocated_ptr = alloc.call(&mut store, len)?;
dbg!(allocated_ptr as *mut u8);
let memory = instance
.get_memory(&mut store, "memory")
.ok_or("no memory")?;
// Write to memory by wasmtime API
memory
.write(
&mut store,
allocated_ptr as usize,
&hello_text.into_bytes_with_nul(),
)
.expect("write failed");
// Mutate data in memory by Module function.
// This function will append " (FIN)" to the string.
// Starting pointer is the same as the one allocated by the module.
let add_end = instance.get_typed_func::<i32, i32>(&mut store, "add_end")?;
let new_len = add_end.call(&mut store, allocated_ptr)?;
// Read by Wasmtime API
let mut read_buf = vec![0_u8; new_len as usize];
memory
.read(&store, allocated_ptr as usize, &mut read_buf)
.expect("read failed");
assert_eq!(read_buf, b"Hello, dear world! (FIN)\0");
// Write to memory by direct access to host memory
let base_ptr = memory.data_ptr(&store);
dbg!(base_ptr);
// offset_ptr is a pointer to the memory allocated by the module in host memory.
let offset_ptr = unsafe { base_ptr.add(allocated_ptr as usize) };
dbg!(offset_ptr);
unsafe {
let new_string = CString::new("Hello, life!")?;
let len = new_string.as_bytes_with_nul().len();
let new_string_ptr = new_string.as_bytes_with_nul().as_ptr();
std::ptr::copy(new_string_ptr, offset_ptr, len);
}
// Mutate data in memory by Module function.
// There for us not interested length of the new string,
// because we read it as CString and it will be null terminated.
let _ = add_end.call(&mut store, offset_ptr as i32)?;
// Read by direct access to host memory
let result = unsafe { CString::from_raw(offset_ptr as *mut _) };
assert_eq!(result.as_bytes_with_nul(), b"Hello, life! (FIN)\0");
forget(result);
// Read all involved memory in examples to see "trash" after the string from first example
let mut read_buf = vec![0_u8; 28];
memory
.read(&store, allocated_ptr as usize, &mut read_buf)
.expect("read failed");
let read_buf = String::from_utf8(read_buf).expect("should be valid String");
dbg!(&read_buf);
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment