Search code examples
rustwebassembly

Why wasm binary code is empty when I create a raw pointer at compile time and use it in a buffer?


I'm trying to build no_std code with wasm32-unknown-unknown target:

#[no_mangle]
pub fn test() {
    let mut idx: i32 = 10;
    let ptr = &mut idx as *mut i32;

    let buffer = unsafe { core::slice::from_raw_parts_mut(ptr, 10) };

    for pixel in buffer.iter_mut() {
        *pixel = 0x7d2b7500;
    }
}

After the build, I get the following wasm binary code (I use wasm2wat tool):

(module
  (type (;0;) (func))
  (func (;0;) (type 0)
    nop)
  (memory (;0;) 16)
  (global (;0;) i32 (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048576))
  (export "memory" (memory 0))
  (export "test" (func 0))
  (export "__data_end" (global 0))
  (export "__heap_base" (global 1)))

My test function is empty for some reason ("nop").

But when I pass a raw pointer ptr from outside as test function argument:

#[no_mangle]
pub fn test(ptr: *mut i32) {
    let buffer = unsafe { core::slice::from_raw_parts_mut(ptr, 10) };

    for pixel in buffer.iter_mut() {
    *pixel = 0x7d2b7500;
    }
}

wasm code generates:

(module
(type (;0;) (func (param i32)))
  (func (;0;) (type 0) (param i32)
    local.get 0
    i64.const 9019431323700000000
    i64.store offset=32 align=4
    local.get 0
    i64.const 9019431323700000000
    i64.store offset=24 align=4
    local.get 0
    i64.const 9019431323700000000
    i64.store offset=16 align=4
    local.get 0
    i64.const 9019431323700000000
    i64.store offset=8 align=4
    local.get 0
    i64.const 9019431323700000000
    i64.store align=4)
  (memory (;0;) 16)
  (global (;0;) i32 (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048576))
  (export "memory" (memory 0))
  (export "test" (func 0))
  (export "__data_end" (global 0))
  (export "__heap_base" (global 1)))

Why it happens?

I'm expecting wasm generated code


Solution

  • You are just modifying local stack memory without returning the value, so it has no side effects and can be optimized out. You could potentially use write_volatile to stop this.

    Your code is also UB because you are not meeting the safety requirements in the documentation for from_raw_parts_mut. In particular

    data must point to len consecutive properly initialized values of type T.