wasm-bindgen: Uncaught DOMException on Firefox when working with vecs in a sub-scope

Description of Bug

When running a function from wasm lib where one has created a std::Vec, the process of pushing an element into this vec from a sub scope causes Firefox to occasionally crash with “”“Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usable “””.

Steps to Reproduce

  1. Construct a function that creates a vec. This cannot be the start function.
  2. In a sub-scope, like a for loop, push an element into the vec.
  3. When in js function call this function
  4. Js function must include a requestAnimationframe function.

Following is a code example that replicates the problem.

lib.rs:

use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
 
 
const WIDTH : usize = 600;
const HEIGHT : usize = 600;
 
#[no_mangle]
static mut BUFFER: [u32; WIDTH * HEIGHT] = [0; WIDTH * HEIGHT];
 
 
#[wasm_bindgen]
pub fn testing()->usize{
//NOTE this is the function of interest.
//It does not matter if we set the capacity of the fector
    let mut v : Vec<f32>= Vec::with_capacity(10);
    v.push(0f32);
    v.push(0f32);
    v.push(0f32);
    let mut _v = 0;
//NOTE
//Error occurs if we are in a for loop or in a normal subscope.
    //{
    for _ in 0..20{
        _v += v[2] as i32;
        v.push(0f32);
    }
    return v.len();
}
 
 
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {unsafe{
 
    let window = web_sys::window().unwrap();
    let document = web_sys::window().unwrap().document().unwrap();
    let canvas = document
        .get_element_by_id("canvas").unwrap()
        .dyn_into::<web_sys::HtmlCanvasElement>()?;
    let body = document.body().expect("document should have a body");
    body.append_child(&canvas)?;
 
    //testing(); //NOTE this is the function of interest
                 //if uncommented the example works
 
 
    Ok(())
}}

index.html:

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
  </head>
  <body>
    <!-- Note the usage of `type=module` here as this is an ES6 module -->
    <script type="module">
 
      import init, { testing } from './pkg/paint.js';
      async function run() {
 
        let wasm = await init('./pkg/paint_bg.wasm');
        const width = 600;
        const height = 600;
 
        const canvas = document.getElementById("canvas");
 
        canvas.width = width;
        canvas.height = height;
 
        const buffer_address = wasm.BUFFER.value;
        const image = new ImageData(
            new Uint8ClampedArray(
                wasm.memory.buffer,
                buffer_address,
                4 * width * height,
            ),
            width,
        );
        testing();
        const ctx = canvas.getContext("2d");
        const render_loop = () => {
 
          ctx.putImageData(image, 0, 0);
          requestAnimationFrame(render_loop);
        };
        render_loop();
 
 
      }
      run();
    </script>
    <canvas id="canvas"></canvas>
  </body>
</html>

Expected Behavior

I expected behavior to be consistent with Chrome, where there were no issues.

Actual Behavior

Crash with the following error: “”“Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usable “””.

Additional Context

Issue specifics:

Bug does not occur when testing in Chrome or using #[test]. Bug does not occur when operations occur within a #[wasm_bindgen(start)] function. Bug does occur when wrapped in function wrapped in a #[wasm_bindgen] called from js. Bug does occur when wrapped in a function and called by a function being called from js. Bug does not occur wrapped in a function, but called from #[wasm_bindgen(start)] function. Bug does not occur if wrapped in a function and called by both #[wasm_bindgen(start)] function and other functions being called from js. Bug occurs if a requestAnimationFrame loop has been created and called. Loop does not have to call offending code, it can be called else where from js. If there is no loop the error does not occur.

tools: + Firefox version 84.0.2 (64-bit) Linux + Chrome version 87.0.4280.88 (64-bit) Linux + rustc version 1.47.0 (18bf6b4f0 2020-10-07) + wasm-pack version 0.9.1 + pythin3 simple server

dependancies: + js-sys “0.3.46” + wasm-bindgen “0.2.69” + web-sys “0.3.4”

compile command: wasm-pack build --release --target web OR wasm-pack build --target web

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 16 (2 by maintainers)

Most upvoted comments

@TKGgunter Yup, can confirm, I get the same effect on v89, I’ll open a crbug report, since they just allowed OOB access to non-existant buffer data in my quick JS example.

You could close the issue if you like, since the Chromium bug isn’t directly related to wasm-bindgen.

Update: Opened https://crbug.com/1193124

Update 2: 8 minutes after having opened the report, it was classified as a security bug, so the above link cannot be viewed, unless you work for Chromium, sorry. The good new is that it might get fixed soon!