[WASM] Exception in memcpy when using a custom allocator

So I am trying to run rust in the browser. I compile to wasm and I want to manage memory on JS side. As a result I provide a malloc implementation that is called by the global allocator:

// These are provided by JS code
#[link(wasm_import_module = "env")]
extern "C" {
  fn malloc(size: usize, align: usize) -> *mut u8;
  fn free(ptr: *const u8);
}

#[global_allocator]
static ALLOCATOR: allocator::WasmAllocator = allocator::WasmAllocator::new();

[...]
unsafe impl GlobalAlloc for WasmAllocator {
  unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
    let size: usize = layout.size();
    let align: usize = layout.align();
    malloc(size, align)
  }

  unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
    free(ptr);
  }
}

However, I get an panic the moment I create a CString from an str:

    let c_str = CString::new(s).unwrap(); // s is a static str

With a stacktrace showing something going wrong in memcpy:

impls.rs:33 Uncaught (in promise) RuntimeError: memory access out of bounds
    at compiler_builtins::mem::impls::copy_forward::copy_forward_bytes::h5ead18430eca9500 (impls.rs:33)
    at compiler_builtins::mem::impls::copy_forward::h82f0e39c8f26f35a (impls.rs:120)
    at compiler_builtins::mem::memcpy::hfdf5bc3991beb596 (mod.rs:26)

I have other allocation before this one that works. I think this is related to the fact that I copy data from the stack to the heap maybe? I am a little lost as to what might be the problem to be honest.

Any help is appreciated.

Does your malloc implementation extend linear memory size as needed?

No I allocate a fix memory size when the page load, but I am far from using all of it. I allocate 64 Mo but when the crash happens my heap pointers is at 0x159030 and I allocate a string of 1 character (2 with the terminating 0) so I don't think it's a problem of capacity.

Do you skip statics, consts, and the soft stack to prevent overwrites?

I initialize by heap pointer this way:

heapPos = mymodule.instance.exports.__heap_base.value;

I assume that would be OK but I am not sure.

That's correct

That's what I was missing in my .cargo/config.toml:

[build]
rustflags = [
  "-C", "link-args=--import-memory",
]
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.