添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
爱跑步的电影票  ·  dpkg-buildpackage: ...·  4 月前    · 
威武的罐头  ·  Java Security ...·  7 月前    · 
谦逊的沙滩裤  ·  我用的android ...·  9 月前    · 

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Describe the Bug

Calling ImageData::new_with_u8_clamped_array() produces a RuntimeError: memory access out of bounds if the provided Clamped<&[u8]> data has 512 * 512 * 4 elements or more:

The same happens when using ImageData::new_with_u8_clamped_array_and_sh() .

Steps to Reproduce

Here is a simple code example that will produce the error:

use wasm_bindgen::{prelude::*, Clamped};
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData};
// Decreasing WIDTH or HEIGHT to 511 or below will make this work
const WIDTH: usize = 512;
const HEIGHT: usize = 512;
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
    let document = web_sys::window().unwrap().document().unwrap();
    let canvas: HtmlCanvasElement = document
        .get_element_by_id("canvas")
        .unwrap()
        .dyn_into()
        .unwrap();
    canvas.set_width(WIDTH as u32);
    canvas.set_height(HEIGHT as u32);
    let context: CanvasRenderingContext2d = canvas
        .get_context("2d")
        .unwrap()
        .unwrap()
        .dyn_into()
        .unwrap();
    let mut pixels: [u8; WIDTH * HEIGHT * 4] = [255; WIDTH * HEIGHT * 4];
    // Fill the pixels array with red
    for y in 0..HEIGHT {
        for x in 0..WIDTH {
            let index = (y * WIDTH + x) * 4;
            if let Some(pixel) = pixels.get_mut(index..index + 4) {
                pixel[0] = 255;
                pixel[1] = 0;
                pixel[2] = 0;
                pixel[3] = 255;
    let clamped_buf = Clamped(pixels.as_ref());
    // This will fail with RuntimeError: memory access out of bounds
    let image_data = ImageData::new_with_u8_clamped_array(clamped_buf, WIDTH as u32)?;
    context.put_image_data(&image_data, 0.0, 0.0)?;
    Ok(())

Expected Behavior

ImageData::new_with_u8_clamped_array() and ImageData::new_with_u8_clamped_array_and_sh() should work with arbitrarily sized data.

Actual Behavior

If the provided data exceeds a certain size (in my case 512 * 512 * 4 elements) a RuntimeError: memory access out of bounds will be thrown.

Additional Context

Tested with wasm-bindgen = "0.2.84" and js-sys = "0.3.61".

Looks like you've run into an odd form of stack overflow.

lld only allocates 1MiB for the WebAssembly stack, and the array that you're allocating on the stack is exactly 1MiB. In combination with the other stuff on the stack, that's causing a stack overflow.

The easiest solution would just be to heap allocate it, with a Vec<u8> or Box<[u8; WIDTH * HEIGHT * 4]>.

If you want, you can also pass a flag to lld to increase the stack size, e.g. with this build.rs:

fn main() {
    // 0x200000 bytes = 2MiB
    println!("cargo:rustc-link-arg=-zstack-size=0x200000")
          

Thanks @Liamolucko, I wasn't aware of the limited stack size. Using a Vec<u8>solved the issue and seems to be a more sustainable and safe solution compared to increasing the stack size:

    let mut pixels: Vec<u8> = vec![255; WIDTH * HEIGHT * 4];