diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 94e23f829..9ddf2c331 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -89,6 +89,10 @@ pub struct Avm1<'gc> { /// If a serious error has occured, or a user has requested it, the AVM may be halted. /// This will completely prevent any further actions from being executed. halted: bool, + + /// The maximum amount of functions that can be called before a `Error::FunctionRecursionLimit` + /// is raised. This defaults to 256 but can be changed per movie. + max_recursion_depth: u16, } unsafe impl<'gc> gc_arena::Collect for Avm1<'gc> { @@ -126,6 +130,7 @@ impl<'gc> Avm1<'gc> { Value::Undefined, ], halted: false, + max_recursion_depth: 255, } } @@ -377,6 +382,14 @@ impl<'gc> Avm1<'gc> { pub fn prototypes(&self) -> &globals::SystemPrototypes<'gc> { &self.prototypes } + + pub fn max_recursion_depth(&self) -> u16 { + self.max_recursion_depth + } + + pub fn set_max_recursion_depth(&mut self, max_recursion_depth: u16) { + self.max_recursion_depth = max_recursion_depth + } } pub fn root_error_handler<'gc>( diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index aea820843..9c1d3a0f8 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -94,7 +94,7 @@ pub struct ActivationIdentifier<'a> { parent: Option<&'a ActivationIdentifier<'a>>, name: Cow<'static, str>, depth: u16, - function_count: u8, + function_count: u16, special_count: u8, } @@ -127,7 +127,7 @@ impl<'a> ActivationIdentifier<'a> { name: name.into(), depth: self.depth + 1, function_count: self.function_count, - special_count: self.function_count, + special_count: self.special_count, } } @@ -135,11 +135,12 @@ impl<'a> ActivationIdentifier<'a> { &'a self, name: S, reason: ExecutionReason, + max_recursion_depth: u16, ) -> Result> { let (function_count, special_count) = match reason { ExecutionReason::FunctionCall => { - if self.function_count == 255 { - return Err(Error::FunctionRecursionLimit); + if self.function_count >= max_recursion_depth - 1 { + return Err(Error::FunctionRecursionLimit(max_recursion_depth)); } (self.function_count + 1, self.special_count) } diff --git a/core/src/avm1/error.rs b/core/src/avm1/error.rs index b42838baf..88de08199 100644 --- a/core/src/avm1/error.rs +++ b/core/src/avm1/error.rs @@ -6,8 +6,8 @@ pub enum Error<'gc> { #[error("Prototype recursion limit has been exceeded")] PrototypeRecursionLimit, - #[error("256 levels of function recursion were exceeded in one action list. This is probably an infinite loop.")] - FunctionRecursionLimit, + #[error("{0} levels of function recursion were exceeded in one action list. This is probably an infinite loop.")] + FunctionRecursionLimit(u16), #[error("66 levels of special recursion were exceeded in one action list. This is probably an infinite loop.")] SpecialRecursionLimit, @@ -23,7 +23,7 @@ impl Error<'_> { pub fn is_halting(&self) -> bool { match self { Error::PrototypeRecursionLimit => true, - Error::FunctionRecursionLimit => true, + Error::FunctionRecursionLimit(_) => true, Error::SpecialRecursionLimit => true, Error::InvalidSwf(_) => true, Error::ThrownValue(_) => false, diff --git a/core/src/avm1/function.rs b/core/src/avm1/function.rs index ff4786c27..6b862d10a 100644 --- a/core/src/avm1/function.rs +++ b/core/src/avm1/function.rs @@ -313,7 +313,9 @@ impl<'gc> Executable<'gc> { let mut frame = Activation::from_action( activation.avm, - activation.id.function(name, reason)?, + activation + .id + .function(name, reason, activation.avm.max_recursion_depth())?, effective_ver, child_scope, af.constant_pool, diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 272b0757e..79135a91d 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -325,6 +325,9 @@ impl<'gc> MovieClip<'gc> { reader, &mut cur_frame, ), + TagCode::ScriptLimits => { + self.0.write(context.gc_context).script_limits(reader, avm) + } TagCode::SoundStreamHead => self .0 .write(context.gc_context) @@ -2065,6 +2068,20 @@ impl<'gc, 'a> MovieClipData<'gc> { Ok(()) } + #[inline] + fn script_limits( + &mut self, + reader: &mut SwfStream<&'a [u8]>, + avm: &mut Avm1<'gc>, + ) -> DecodeResult { + let max_recursion_depth = reader.read_u16()?; + let _timeout_in_seconds = reader.read_u16()?; + + avm.set_max_recursion_depth(max_recursion_depth); + + Ok(()) + } + #[inline] fn export_assets( &mut self, diff --git a/core/tests/swfs/avm1/infinite_recursion_function/output.txt b/core/tests/swfs/avm1/infinite_recursion_function/output.txt index 8e71b70a6..bccb45287 100644 --- a/core/tests/swfs/avm1/infinite_recursion_function/output.txt +++ b/core/tests/swfs/avm1/infinite_recursion_function/output.txt @@ -2,254 +2,3 @@ // start of recursive() function // start of recursive() function // start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function -// start of recursive() function diff --git a/core/tests/swfs/avm1/infinite_recursion_function/test.fla b/core/tests/swfs/avm1/infinite_recursion_function/test.fla index 26a131523..c0659d9da 100644 Binary files a/core/tests/swfs/avm1/infinite_recursion_function/test.fla and b/core/tests/swfs/avm1/infinite_recursion_function/test.fla differ diff --git a/core/tests/swfs/avm1/infinite_recursion_function/test.swf b/core/tests/swfs/avm1/infinite_recursion_function/test.swf index 6fd1fcbea..dcd037bcd 100644 Binary files a/core/tests/swfs/avm1/infinite_recursion_function/test.swf and b/core/tests/swfs/avm1/infinite_recursion_function/test.swf differ