mirror of
https://github.com/servo/servo.git
synced 2025-06-06 00:25:37 +00:00
pixels: Add limitation to max image total bytes length (#37172)
Limit the maximum image allocation size to 2GB to minimize the possibility of out of memory errors on some `ImageBitmap`, `ImageData`, `Canvas`, and `OffscreenCanvas` operations such as construction, `toBlob`, and `toDataURL`. Other browsers have similar limits: - Chromium: 2^32-1 (~4GB) - Firefox: 2^31-1 (~2GB) Testing: Improvements to the following tests: - `html/canvas/element/pixel-manipulation/2d.imageData.object.ctor.basics.html` assert_throws_dom("INDEX_SIZE_ERR", function() { new ImageData(1 << 31, 1 << 31); }); - `html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html` makeOversizedCanvas + makeOversizedOffscreenCanvas Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
3bb7c71eb6
commit
801ac9e22a
6 changed files with 93 additions and 150 deletions
|
@ -31,6 +31,20 @@ pub enum PixelFormat {
|
|||
BGRA8,
|
||||
}
|
||||
|
||||
// Computes image byte length, returning None if overflow occurred or the total length exceeds
|
||||
// the maximum image allocation size.
|
||||
pub fn compute_rgba8_byte_length_if_within_limit(width: usize, height: usize) -> Option<usize> {
|
||||
// Maximum allowed image allocation size (2^31-1 ~ 2GB).
|
||||
const MAX_IMAGE_BYTE_LENGTH: usize = 2147483647;
|
||||
|
||||
// The color components of each pixel must be stored in four sequential
|
||||
// elements in the order of red, green, blue, and then alpha.
|
||||
4usize
|
||||
.checked_mul(width)
|
||||
.and_then(|v| v.checked_mul(height))
|
||||
.filter(|v| *v <= MAX_IMAGE_BYTE_LENGTH)
|
||||
}
|
||||
|
||||
pub fn rgba8_get_rect(pixels: &[u8], size: Size2D<u64>, rect: Rect<u64>) -> Cow<[u8]> {
|
||||
assert!(!rect.is_empty());
|
||||
assert!(Rect::from_size(size).contains_rect(&rect));
|
||||
|
|
|
@ -2982,10 +2982,13 @@ impl GlobalScope {
|
|||
return p;
|
||||
}
|
||||
|
||||
if let Some(snapshot) = canvas.get_image_data() {
|
||||
let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
|
||||
image_bitmap.set_origin_clean(canvas.origin_is_clean());
|
||||
p.resolve_native(&(image_bitmap), can_gc);
|
||||
match canvas.get_image_data() {
|
||||
Some(snapshot) => {
|
||||
let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
|
||||
image_bitmap.set_origin_clean(canvas.origin_is_clean());
|
||||
p.resolve_native(&(image_bitmap), can_gc);
|
||||
},
|
||||
None => p.reject_error(Error::InvalidState, can_gc),
|
||||
}
|
||||
p
|
||||
},
|
||||
|
@ -2996,10 +2999,13 @@ impl GlobalScope {
|
|||
return p;
|
||||
}
|
||||
|
||||
if let Some(snapshot) = canvas.get_image_data() {
|
||||
let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
|
||||
image_bitmap.set_origin_clean(canvas.origin_is_clean());
|
||||
p.resolve_native(&(image_bitmap), can_gc);
|
||||
match canvas.get_image_data() {
|
||||
Some(snapshot) => {
|
||||
let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
|
||||
image_bitmap.set_origin_clean(canvas.origin_is_clean());
|
||||
p.resolve_native(&(image_bitmap), can_gc);
|
||||
},
|
||||
None => p.reject_error(Error::InvalidState, can_gc),
|
||||
}
|
||||
p
|
||||
},
|
||||
|
|
|
@ -362,7 +362,13 @@ impl HTMLCanvasElement {
|
|||
Some(context) => context.get_image_data(),
|
||||
None => {
|
||||
let size = self.get_size();
|
||||
if size.width == 0 || size.height == 0 {
|
||||
if size.is_empty() ||
|
||||
pixels::compute_rgba8_byte_length_if_within_limit(
|
||||
size.width as usize,
|
||||
size.height as usize,
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(Snapshot::cleared(size.cast()))
|
||||
|
|
|
@ -41,14 +41,11 @@ impl ImageData {
|
|||
mut data: Option<Vec<u8>>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DomRoot<ImageData>> {
|
||||
// The color components of each pixel must be stored in four sequential
|
||||
// elements in the order of red, green, blue, and then alpha.
|
||||
let len = 4u32
|
||||
.checked_mul(width)
|
||||
.and_then(|v| v.checked_mul(height))
|
||||
.ok_or(Error::Range(
|
||||
"The requested image size exceeds the supported range".to_owned(),
|
||||
))?;
|
||||
let len =
|
||||
pixels::compute_rgba8_byte_length_if_within_limit(width as usize, height as usize)
|
||||
.ok_or(Error::Range(
|
||||
"The requested image size exceeds the supported range".to_owned(),
|
||||
))?;
|
||||
|
||||
unsafe {
|
||||
let cx = GlobalScope::get_cx();
|
||||
|
@ -129,18 +126,16 @@ impl ImageData {
|
|||
return Err(Error::IndexSize);
|
||||
}
|
||||
|
||||
// The color components of each pixel must be stored in four sequential
|
||||
// elements in the order of red, green, blue, and then alpha.
|
||||
// Please note when a too-large ImageData is created using a constructor
|
||||
// historically throwns an IndexSizeError, instead of RangeError.
|
||||
let len = 4u32
|
||||
.checked_mul(width)
|
||||
.and_then(|v| v.checked_mul(height))
|
||||
.ok_or(Error::IndexSize)?;
|
||||
// When a constructor is called for an ImageData that is too large, other browsers throw
|
||||
// IndexSizeError rather than RangeError here, so we do the same.
|
||||
let len =
|
||||
pixels::compute_rgba8_byte_length_if_within_limit(width as usize, height as usize)
|
||||
.ok_or(Error::IndexSize)?;
|
||||
|
||||
let cx = GlobalScope::get_cx();
|
||||
|
||||
let heap_typed_array = create_heap_buffer_source_with_length::<ClampedU8>(cx, len, can_gc)?;
|
||||
let heap_typed_array =
|
||||
create_heap_buffer_source_with_length::<ClampedU8>(cx, len as u32, can_gc)?;
|
||||
|
||||
let imagedata = Box::new(ImageData {
|
||||
reflector_: Reflector::new(),
|
||||
|
|
|
@ -92,7 +92,13 @@ impl OffscreenCanvas {
|
|||
Some(context) => context.get_image_data(),
|
||||
None => {
|
||||
let size = self.get_size();
|
||||
if size.width == 0 || size.height == 0 {
|
||||
if size.is_empty() ||
|
||||
pixels::compute_rgba8_byte_length_if_within_limit(
|
||||
size.width as usize,
|
||||
size.height as usize,
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(Snapshot::cleared(size))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[createImageBitmap-invalid-args.html]
|
||||
expected: CRASH
|
||||
expected: ERROR
|
||||
[createImageBitmap with a vector HTMLImageElement source and sw set to 0]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -10,16 +10,13 @@
|
|||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a broken image source.]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with WebGLRenderingContext image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a Blob source and sw set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an available but zero height image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and sh set to 0]
|
||||
expected: FAIL
|
||||
|
@ -28,25 +25,19 @@
|
|||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a Blob source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and sw set to 0]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with null image source.]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an ImageData source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with undefined image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an undecodable blob source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an available but undecodable image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and oversized (unallocatable) crop region]
|
||||
expected: FAIL
|
||||
|
@ -55,13 +46,13 @@
|
|||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLCanvasElement source and oversized (unallocatable) crop region]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and oversized (unallocatable) crop region]
|
||||
expected: FAIL
|
||||
|
@ -70,187 +61,112 @@
|
|||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageData source and sw set to 0]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an invalid OffscreenCanvas source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and sw set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and sh set to 0]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageData source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with ArrayBuffer image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an oversized canvas source.]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with Uint8Array image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLCanvasElement source and sh set to 0]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a closed ImageBitmap.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap HTMLImageElement source and oversized (unallocatable) crop region]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with empty image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with empty video source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and sw set to 0]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an available but zero width image source.]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and sw set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a Blob source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and sh set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and sw set to 0]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap HTMLImageElement source and sw set to 0]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and oversized (unallocatable) crop region]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with CanvasRenderingContext2D image source.]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a vector HTMLImageElement source and a value of 0 int resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector HTMLImageElement source and a value between 0 and 1 in resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an ImageData source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an ImageData source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and a value between 0 and 1 in resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
[createImageBitmap with a vector SVGImageElement source and a value of 0 int resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value of 0 int resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a Blob source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and a value of 0 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and a value between 0 and 1 in resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a Blob source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a Blob source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a vector HTMLImageElement source and a value between 0 and 1 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and a value of 0 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and a value between 0 and 1 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement source and a value of 0 int resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a vector HTMLImageElement source and a value of 0 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an OffscreenCanvas source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a bitmap SVGImageElement source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and a value of 0 int resizeWidth]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageData source and a value between 0 and 1 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with an HTMLVideoElement from a data URL source and a value between 0 and 1 in resizeHeight]
|
||||
expected: FAIL
|
||||
|
||||
[createImageBitmap with an ImageData source and a value of 0 int resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a vector SVGImageElement source and a value between 0 and 1 in resizeWidth]
|
||||
expected: NOTRUN
|
||||
|
||||
[createImageBitmap with a Blob source and a value of 0 in resizeHeight]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue