How to deallocate WASM heap memory that is exported to Javascript

I was trying to find a way to export vector or other heap alocated data to Javascript. I tried this:

use wasm_bindgen::prelude::*;
use std::alloc::{Layout, dealloc};

#[wasm_bindgen]
pub struct ArrayBuffer {
    ptr: *const u8,
    len: usize,
}

#[wasm_bindgen]
impl ArrayBuffer {
    #[wasm_bindgen(getter)]
    pub fn ptr(&self) -> *const u8 {
        self.ptr
    }

    #[wasm_bindgen(getter)]
    pub fn len(&self) -> usize {
        self.len
    }
}

#[wasm_bindgen]
pub fn get_array() -> ArrayBuffer {
    let data = vec![1, 2, 3, 4, 5];
    let ptr = data.as_ptr();
    let len = data.len();

    std::mem::forget(data);

    ArrayBuffer { ptr, len }
}

#[wasm_bindgen]
pub fn free_array_raw(ptr: *mut u8, len: usize) {
    unsafe {
        let mut v = Vec::from_raw_parts(ptr, len, len);
        v.fill(0); 
        drop(v);  
    }
}

The I compile with wasm-pack targetting nodejs

wasm-pack build --target nodejs

Here is my Javascript code I used to test it

const wasm = require('./pkg/wasm.js');

async function run() {
  const arrayBuffer = wasm.get_array();
  const ptr = arrayBuffer.ptr;
  const len = arrayBuffer.len;

  const memory = wasm.__wasm.memory;

  const uint8Array = new Uint8Array(memory.buffer, ptr, len);

  console.log(uint8Array);

  arrayBuffer.free();
  wasm.free_array_raw(ptr, len);
  
  console.log(uint8Array);
}

run().catch(console.error);

The memory does not get deallocated, I still can access the data

[root@localhost wasm]# node ./main.js
Uint8Array(5) [ 1, 2, 3, 4, 5 ]
Uint8Array(5) [ 1, 2, 3, 4, 5 ]

How is the correct way to deallocate the heap memory?

Just because some heap memory is deallocated, doesn't mean that trying to access the same address is guaranteed to fail. It is UB to access, but as with all UB, it can do anything including just so happening to do what you want it to do. And in fact in wasm, there is no way to physically cause part of the heap to become inaccessible (you can't shrink a linear memory or unmap part of it), it can only be reused for another heap allocation.

1 Like

Thank youu, that was my missunderstanding of how WASM memory allocation works :<