Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

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

web_sys::ImageData Constructor is Not Sound #2445

Closed
anlumo opened this issue Feb 4, 2021 · 3 comments
Closed

web_sys::ImageData Constructor is Not Sound #2445

anlumo opened this issue Feb 4, 2021 · 3 comments
Labels

Comments

@anlumo
Copy link

anlumo commented Feb 4, 2021

Describe the Bug

The two constructors for web_sys::ImageData take a Clamped<&[u8]>, which is a reference. However, ImageData does not copy this data to its own buffer, so the resulting JS object depends on local data in a way that the Rust compiler is not aware of it.

Steps to Reproduce

Example code:

use wasm_bindgen::Clamped;
use web_sys::ImageData;

#[wasm_bindgen]
pub fn foo() -> ImageData {
    let bitmap = vec![0u8; 100 *100 * 4];
    ImageData::new_with_u8_clamped_array_and_sh(Clamped(&bitmap), 100, 100)
}

Then use that code in a wasm module and call it from JavaScript. In JavaScript, store that ImageData and use it for a while.

Expected Behavior

The ImageData stays the same.

Actual Behavior

After a few operations on the wasm side, data corruption in the ImageData occurs.

In our project, it looks like this:
image

The noise above used to be proper text.

Additional Context

A workaround would be to create a new Uint8ClampedArray and store it there, since then the JS runtime is responsible for memory management. However, unlike in JavaScript directly, in web_sys there is no constructor exposed that can take a Uint8ClampedArray.

What works for me is to return a Uint8ClampedArray, width and height from the function instead and construct the ImageData on the JavaScript side. However, this is not a general solution since sometimes you might want to use the ImageData directly in Rust.

Also, the two constructors of ImageData exposed right now should be marked as unsafe, since they're not making sure that the data referenced is staying alive during the runtime of the ImageData.

@anlumo anlumo added the bug label Feb 4, 2021
@anlumo
Copy link
Author

anlumo commented Feb 4, 2021

Related to #423

@alexcrichton
Copy link
Contributor

Unfortunately I think this is an example where we can't guarantee that everything in web-sys is 100% safe. We do our best but sometimes you'll also need to be aware of what API is being called. We could try to whitelist these perhaps to do some copies as well, but that's not necessarily always desired.

In general I'm not really sure what a fix for this would look like, if any.

Herschel added a commit to Herschel/ruffle that referenced this issue May 22, 2022
 * Remove `BitmapDataStorage` as its no longer necessary, and store
   the bitmap canvas/context in `BitmapData` instead.
 * Store the `Bitmap` RBGA buffer in the canvas backend. Previously
   this was thrown away when converted to `ImageData`, but this
   causes the glitchy pixels mentioned in:
   ruffle-rs#6975 (comment)
   `ImageData` does not copy the buffer passed to it, so store it
   to keep it alive. See:
   rustwasm/wasm-bindgen#2445
Herschel added a commit to ruffle-rs/ruffle that referenced this issue May 22, 2022
 * Remove `BitmapDataStorage` as its no longer necessary, and store
   the bitmap canvas/context in `BitmapData` instead.
 * Store the `Bitmap` RBGA buffer in the canvas backend. Previously
   this was thrown away when converted to `ImageData`, but this
   causes the glitchy pixels mentioned in:
   #6975 (comment)
   `ImageData` does not copy the buffer passed to it, so store it
   to keep it alive. See:
   rustwasm/wasm-bindgen#2445
@daxpedda
Copy link
Collaborator

daxpedda commented Nov 7, 2024

Closing as duplicate of #423.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants