Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript ArrayBuffer "detaches" when constructing a new Rust Vec via WASM

The basic idea is that a pointer is returned and then an image will be displayed using the pointer after creating a Vec at each video frame:

JavaScript:

var ptr = exports.alloc(size);
let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
let image = new ImageData(bytes, 320, 240);

function tick() {
    requestAnimationFrame(tick);
    ctx.drawImage(video, 0, 0, width, height);
    let imageData = ctx.getImageData(0, 0, width, height).data;
    bytes.set(imageData);
    exports.create_vector();
    ctx.putImageData(img, 0, 0);
}

Rust:

#[no_mangle]
pub extern "C" fn alloc(capacity: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(capacity);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn create_vector() {
    let _: Vec<u8> = Vec::with_capacity(320 * 240);
}

Here is the actual code.

Here are the error messages:

Chrome:

Uncaught TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer
    at Uint8ClampedArray.set (<anonymous>)
    at tick

Safari:

This webpage was reloaded because a problem occurred

Mozilla:

DOMException: "An attempt was made to use an object that is not, or is no longer, usable"

TypeError: Underlying ArrayBuffer has been detached from the view

The main culprits seem to be:

let bytes = new Uint8ClampedArray(exports.memory.buffer, ptr, size);
// ...
    exports.create_vector();
// ...

i.e., the browser crashes when I try to use ptr again after calling exports.create_vector.

What is going wrong here? Is there a solution?

like image 970
user8034246 Avatar asked Sep 05 '26 05:09

user8034246


1 Answers

When you allocate a new buffer and there is not enough memory allocated by the WASM "process" for it, the browser will allocate a new, larger buffer and will copy all data into it from the old location. It's quite transparent inside the WASM interpreter, but all pointers passed to JavaScript (with which you construct Uint8ClampedArray) get invalidated. There are two solutions to my knowledge:

  • Allocate enough memory in the WASM "process" at initialization and immediately deallocate it so pointers will not get invalidated so long as memory usage is lower than the selected size.
  • Keep track of buffers passed to JavaScript and "renew" pointers on such errors.
like image 184
guest4e2 Avatar answered Sep 06 '26 18:09

guest4e2



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!