Using memory pointers

In this example we will learn how to pass data between the host system and Wasm using memory pointers.
Linear memory is a major concept in WebAssembly:
Because WebAssembly is sandboxed, memory must be copied between the host (your Rust application) and the Wasm module. Upcoming proposals like WebAssembly Interface Types will make this process much easier, but it is still a work in progress.
The way that this memory is allocated, freed, passed, organized, etc... can vary depending on the ABI of the Wasm module.
For example, some ABIs will provide functions, either as imports or exports, for allocation and freeing of memory from the host or guest. Some Wasm ABIs may want to control their memory implicitly, for example the ABI may say that the host can reserve memory addresses 0 to 1000 for a special purpose and simply write there directly. You will want to take a look at the documentation of the ABI of your Wasm module, to see what conventions are used for memory allocation.
In this example, let's say we have a Wasm module that can perform transformations on a string passed into the module's memory. This module exports a function that returns a pointer to a fixed size static buffer. This Wasm module will take in a string, and append the string " Wasm is cool!" to the end. This example shows how we can read and write memory from the host (your Rust application), and how the Wasm module can also read and write to the same memory.
First we are going to want to initialize a new project. To do this we can navigate to our project folder, or create one. In this example, we will create a new project. Lets create it and navigate to it:
The final Rust code for this example can be found on Github:
Please take a look at the setup steps for Rust.
cargo new exported-memory
cd exported-memory
We have to modify Cargo.toml to add the Wasmer dependencies as shown below:
# The Wasmer API
wasmer = "3.0"
The final Ruby code for this example can be found on Github: exports_memory.rb.
Please take a look at the setup steps for Ruby.
gem install wasmer
Now that we have everything set up, let's go ahead and try it out!
Before you go further in this example, it is recommended you read the example on the basics of interacting with guest memory:

Reading the memory

The guest module exports a bunch of things that will be useful for us:
  • A memory exported as mem;
  • A function to retrieve information about the memory contents exported as load.
The load function will return two things: the offset of the contents and its length. Let's see how we can use that to read the memory.
let load: TypedFunction<(), (WasmPtr<u8>, i32)> =
instance.exports.get_typed_function(&mut store, "load")?;
let memory = instance.exports.get_memory("mem")?;
When importing the function we tell Wasmer that it return a WasmPtr as its first return value. This WasmPtr is what will give us the ability to interact with the memory.
let (ptr, length) = store)?;
println!("String offset: {:?}", ptr.offset());
println!("String length: {:?}", length);
memory = instance.exports.mem
Let's call the hello exported function: it will return what we'll call a pointer.
pointer = instance.exports.hello.()
This pointer is actually just an integer which is the position in the memory where we'll find our data.
Now that we have our pointer, let's read the data. We know we are about to read a string and the load function gave us its length. We have everything we need!
let memory_view = memory.view(&store);
let str = ptr.read_utf8_string(&memory_view, length as u32).unwrap();
println!("Memory contents: {:?}", str);
reader = memory.uint8_view pointer
returned_string = reader.take(13).pack("U*")
raise "Error" unless returned_string == 'Hello, World!'
Done! We were able to get a string out of the Wasm module memory.

Writing to the memory

It's now time to write a new string int the guest module's memory. To do that will continue using our pointer.
What we do here is get a slice of Cells: we want this slice to be the size of the new string starting at the same offset as our pointer. This allows us to completely overwrite the old string with the new one.
We could have just changed a single word in the old string. To do that we would have changed the offset and length of the slice when dereferencing the pointer. Here is how we would have done the dereferencing part if we wanted to only change the "World!" part:
let new_str = b"Wasmer!";
let (mut ptr, length) = store)?;
let values = ptr.slice(&memory_view, new_str.len() as u32).unwrap();
for i in 0..new_str.len() {
values.index(i as u64).write(new_str[i]).unwrap();


We now have everything we need to run the Wasm module, let's do it!
Compiling module...
Instantiating module...
Memory size (pages) 1 pages
Memory size (bytes) 65536
String offset: 42
String length: 13
Memory contents: "Hello, World!"
New string length: 14
New memory contents: "Hello, Wasmer!"
If you want to run the examples from the Wasmer repository codebase directly, you can also do:
git clone
cd wasmer
cargo run --example exported-memory --release --features "cranelift"
You should be able to run it using the ruby instance.rb command.
If you want to run the examples from the Wasmer Ruby repository codebase directly, you can also do:
git clone
cd wasmer-ruby
ruby examples/exports_memory.rb