From 2d3a4910fcfbc3dfefc748855c5dc6c69538fd85 Mon Sep 17 00:00:00 2001 From: relrelb Date: Sat, 24 Apr 2021 19:04:35 +0300 Subject: [PATCH] avm1: Correct BitmapData constructor * Extract is_size_valid, which respects 3 different limits: SWF<=9, SWF10 and SWF>=11. * Delay is_size_valid check after all arguments coercing. * Swap the transparency and fill_color parameters of init_pixels. --- core/src/avm1/globals/bitmap_data.rs | 45 +++++++++++++++++++++------- core/src/avm1/object/bitmap_data.rs | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/core/src/avm1/globals/bitmap_data.rs b/core/src/avm1/globals/bitmap_data.rs index bb2ead2bb..1a0533990 100644 --- a/core/src/avm1/globals/bitmap_data.rs +++ b/core/src/avm1/globals/bitmap_data.rs @@ -10,6 +10,31 @@ use crate::character::Character; use crate::display_object::TDisplayObject; use gc_arena::{GcCell, MutationContext}; +fn is_size_valid(swf_version: u8, width: u32, height: u32) -> bool { + // From https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html: + // "In AIR 1.5 and Flash Player 10, the maximum size for a BitmapData object is 8,191 pixels in + // width or height, and the total number of pixels cannot exceed 16,777,215 pixels. (So, if a + // BitmapData object is 8,191 pixels wide, it can only be 2,048 pixels high.) In Flash Player 9 + // and earlier and AIR 1.1 and earlier, the limitation is 2,880 pixels in height and 2,880 in width. + // Starting with AIR 3 and Flash player 11, the size limits for a BitmapData object have been removed. + // The maximum size of a bitmap is now dependent on the operating system." + // + // In addition, width and height of 0 are invalid in all versions. + if width == 0 || height == 0 { + return false; + } + if swf_version <= 9 { + if width > 2880 || height > 2880 { + return false; + } + } else if swf_version == 10 { + if width >= 0x2000 || height >= 0x2000 || width * height >= 0x1000000 { + return false; + } + } + true +} + pub fn constructor<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, @@ -18,17 +43,12 @@ pub fn constructor<'gc>( let width = args .get(0) .unwrap_or(&Value::Number(0.0)) - .coerce_to_i32(activation)?; + .coerce_to_i32(activation)? as u32; let height = args .get(1) .unwrap_or(&Value::Number(0.0)) - .coerce_to_i32(activation)?; - - if width > 2880 || height > 2880 || width <= 0 || height <= 0 { - log::warn!("Invalid BitmapData size {}x{}", width, height); - return Ok(Value::Undefined); - } + .coerce_to_i32(activation)? as u32; let transparency = args .get(2) @@ -37,16 +57,19 @@ pub fn constructor<'gc>( let fill_color = args .get(3) - // can't write this in hex - // 0xFFFFFFFF as f64; - .unwrap_or(&Value::Number(4294967295_f64)) + .unwrap_or(&Value::Number(4294967295f64)) // 0xFFFFFFFF .coerce_to_i32(activation)?; + if !is_size_valid(activation.swf_version(), width, height) { + log::warn!("Invalid BitmapData size: {}x{}", width, height); + return Ok(Value::Undefined); + } + if let Some(bitmap_data) = this.as_bitmap_data_object() { bitmap_data .bitmap_data() .write(activation.context.gc_context) - .init_pixels(width as u32, height as u32, fill_color, transparency); + .init_pixels(width, height, transparency, fill_color); } Ok(this.into()) diff --git a/core/src/avm1/object/bitmap_data.rs b/core/src/avm1/object/bitmap_data.rs index b00d11f9e..d45fe88da 100644 --- a/core/src/avm1/object/bitmap_data.rs +++ b/core/src/avm1/object/bitmap_data.rs @@ -164,7 +164,7 @@ pub struct BitmapData { } impl BitmapData { - pub fn init_pixels(&mut self, width: u32, height: u32, fill_color: i32, transparency: bool) { + pub fn init_pixels(&mut self, width: u32, height: u32, transparency: bool, fill_color: i32) { self.width = width; self.height = height; self.transparency = transparency;