1

I'm using wasm-bindgen to build a simple Rust struct with constructor that takes a JS closure, and run it in node.js.

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct WasmThing {
    func: Box<dyn FnMut()>,
}

#[wasm_bindgen]
impl WasmThing {
    #[wasm_bindgen(constructor)]
    pub fn new(js_func: js_sys::Function) -> WasmThing {
        WasmThing {
            func: Box::new(move || {
                js_func.call0(&wasm_bindgen::JsValue::UNDEFINED).unwrap();
            }),
        }
    }
}

I then run wasm-pack to create a package I can import with this WASM.

In my node.js code, I then create many instances of this WasmThing:

while (true) {
  const thing = new WasmThing(() => {
    console.log("Hello there!");
  });
  thing.free();
}

This works for some time, but after ~250 loop iterations I always see this crash when trying to instantiate any more:

RuntimeError: Memory Access out of bounds
  at wasm://wasm/0168863a:wasm-function[7107]:0x3ffc48
  at wasm://wasm/0168863a:wasm-function[137]:0x100fa1
  at new WasmThing (/home/ari/src/wasm-fail/index.js:1)

Both the Node profiler (thru Chrome Devtools) and my actual OS task manager don't show a rise in memory usage before or after happens.

I've tried using the new wasm-bindgen weakref support, in case something didn't get garbage collected, but it didn't help.

It happens on multiple JS engines - in Node, in Chrome, and in WebKit - so it's not just a V8 bug. I haven't managed to reproduce it in Firefox.

My best guess right now is that either the closure's not getting garbage collected, somehow, or that there's some internal WASM memory type that isn't backed by real (virtual) memory that I'm running out of.

Any ideas on how to continue debugging?

Ari Lotter
  • 605
  • 8
  • 23
  • https://github.com/rust-lang/const-eval/issues/20 – محمد جعفر نعمة Aug 09 '22 at 05:29
  • 1
    Crash at ~250 loops smells overflow of bytesize counter. Other thing looking at the code [js_sys::Function.call1](https://rustwasm.github.io/wasm-bindgen/api/js_sys/struct.Function.html#method.call1) takes a context and an argument as arguments. I dont get this to match the snippet above. Js function `() => {...}` match `.call0` and only one parameter to `js_func.call1(&wasm_bindgen::JsValue::UNDEFINED)` where the api specifies 2. – Jonas Bojesen Aug 09 '22 at 11:30
  • On Ubuntu 21.10, Chrome 104. Modified [without-a-bundler](https://github.com/rustwasm/wasm-bindgen/tree/main/examples/without-a-bundler) to reproduce crash above. Successfully allocated WasmThing in iterations loop of 100, 1000 and 10000 without reproducing the crash above. – Jonas Bojesen Aug 10 '22 at 09:13
  • 1
    @JonasBojesen I think I have it figured out, and my example is incomplete. Will update in the next few days. – Ari Lotter Aug 10 '22 at 17:07
  • @AriLotter if you were able to figure out a solution, would you mind posting it as an answer? And if there was context missing from your original post can you edit that in as well? – kmdreko Sep 21 '22 at 19:51

0 Answers0