Using linear memory

You can also browse this source code online and clone the wasmtime repository to run the example locally.

This example shows off how to interact with wasm memory in a module. Be sure to read the documentation for Memory as well.

memory.wat

(module
  (memory (export "memory") 2 3)

  (func (export "size") (result i32) (memory.size))
  (func (export "load") (param i32) (result i32)
    (i32.load8_s (local.get 0))
  )
  (func (export "store") (param i32 i32)
    (i32.store8 (local.get 0) (local.get 1))
  )

  (data (i32.const 0x1000) "\01\02\03\04")
)

memory.rs

//! An example of how to interact with wasm memory.
//!
//! Here a small wasm module is used to show how memory is initialized, how to
//! read and write memory through the `Memory` object, and how wasm functions
//! can trap when dealing with out-of-bounds addresses.

// You can execute this example with `cargo run --example example`

use anyhow::Result;
use wasmtime::*;

fn main() -> Result<()> {
    // Create our `Store` context and then compile a module and create an
    // instance from the compiled module all in one go.
    let wasmtime_store = Store::default();
    let module = Module::from_file(wasmtime_store.engine(), "examples/memory.wat")?;
    let instance = Instance::new(&wasmtime_store, &module, &[])?;

    // Load up our exports from the instance
    let memory = instance
        .get_memory("memory")
        .ok_or(anyhow::format_err!("failed to find `memory` export"))?;
    let size = instance
        .get_func("size")
        .ok_or(anyhow::format_err!("failed to find `size` export"))?
        .get0::<i32>()?;
    let load = instance
        .get_func("load")
        .ok_or(anyhow::format_err!("failed to find `load` export"))?
        .get1::<i32, i32>()?;
    let store = instance
        .get_func("store")
        .ok_or(anyhow::format_err!("failed to find `store` export"))?
        .get2::<i32, i32, ()>()?;

    // Note that these memory reads are *unsafe* due to unknown knowledge about
    // aliasing with wasm memory. For more information about the safety
    // guarantees here and how to use `Memory` safely, see the API
    // documentation.
    println!("Checking memory...");
    assert_eq!(memory.size(), 2);
    assert_eq!(memory.data_size(), 0x20000);
    unsafe {
        assert_eq!(memory.data_unchecked_mut()[0], 0);
        assert_eq!(memory.data_unchecked_mut()[0x1000], 1);
        assert_eq!(memory.data_unchecked_mut()[0x1003], 4);
    }

    assert_eq!(size()?, 2);
    assert_eq!(load(0)?, 0);
    assert_eq!(load(0x1000)?, 1);
    assert_eq!(load(0x1003)?, 4);
    assert_eq!(load(0x1ffff)?, 0);
    assert!(load(0x20000).is_err()); // out of bounds trap

    println!("Mutating memory...");
    unsafe {
        memory.data_unchecked_mut()[0x1003] = 5;
    }

    store(0x1002, 6)?;
    assert!(store(0x20000, 0).is_err()); // out of bounds trap

    unsafe {
        assert_eq!(memory.data_unchecked_mut()[0x1002], 6);
        assert_eq!(memory.data_unchecked_mut()[0x1003], 5);
    }
    assert_eq!(load(0x1002)?, 6);
    assert_eq!(load(0x1003)?, 5);

    // Grow memory.
    println!("Growing memory...");
    memory.grow(1)?;
    assert_eq!(memory.size(), 3);
    assert_eq!(memory.data_size(), 0x30000);

    assert_eq!(load(0x20000)?, 0);
    store(0x20000, 0)?;
    assert!(load(0x30000).is_err());
    assert!(store(0x30000, 0).is_err());

    assert!(memory.grow(1).is_err());
    assert!(memory.grow(0).is_ok());

    println!("Creating stand-alone memory...");
    let memorytype = MemoryType::new(Limits::new(5, Some(5)));
    let memory2 = Memory::new(&wasmtime_store, memorytype);
    assert_eq!(memory2.size(), 5);
    assert!(memory2.grow(1).is_err());
    assert!(memory2.grow(0).is_ok());

    Ok(())
}