avm1: Stop execution if base clip is removed (fix #893)

Stop execution of the current stack frame if the base clip was
removed (for example, due to a goto).
This commit is contained in:
Mike Welsh 2020-10-14 18:18:43 -07:00
parent 3f46567fc1
commit 0482d1c290
1 changed files with 24 additions and 15 deletions

View File

@ -678,7 +678,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
avm_warn!(self, "CloneSprite: Source is not a movie clip"); avm_warn!(self, "CloneSprite: Source is not a movie clip");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_bit_and(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_bit_and(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -796,7 +796,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
self.context.avm1.push(result); self.context.avm1.push(result);
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_call_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_call_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -834,7 +834,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} }
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_cast_op(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_cast_op(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1201,8 +1201,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
e e
), ),
} }
return self.continue_if_base_clip_exists();
return Ok(FrameControl::Continue);
} }
if let Some(fscommand) = fscommand::parse(url) { if let Some(fscommand) = fscommand::parse(url) {
@ -1291,8 +1290,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
self.context.navigator.spawn_future(process); self.context.navigator.spawn_future(process);
} }
} }
return self.continue_if_base_clip_exists();
return Ok(FrameControl::Continue);
} else if window_target.starts_with("_level") && url.len() > 6 { } else if window_target.starts_with("_level") && url.len() > 6 {
// target of `_level#` indicates a `loadMovieNum` call. // target of `_level#` indicates a `loadMovieNum` call.
match window_target[6..].parse::<u32>() { match window_target[6..].parse::<u32>() {
@ -1344,7 +1342,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_error!(self, "GotoFrame failed: Invalid target"); avm_error!(self, "GotoFrame failed: Invalid target");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_goto_frame_2( fn action_goto_frame_2(
@ -1370,7 +1368,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_warn!(self, "GotoFrame2: Invalid target"); avm_warn!(self, "GotoFrame2: Invalid target");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_goto_label(&mut self, label: &str) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_goto_label(&mut self, label: &str) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1387,7 +1385,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_warn!(self, "GoToLabel: Invalid target"); avm_warn!(self, "GoToLabel: Invalid target");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_if( fn action_if(
@ -1615,7 +1613,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_warn!(self, "NextFrame: Invalid target"); avm_warn!(self, "NextFrame: Invalid target");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_new_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_new_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1643,7 +1641,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
self.context.avm1.push(Value::Undefined); self.context.avm1.push(Value::Undefined);
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_new_object(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_new_object(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1662,7 +1660,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
self.context.avm1.push(this); self.context.avm1.push(this);
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_or(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_or(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1698,7 +1696,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_warn!(self, "PrevFrame: Invalid target"); avm_warn!(self, "PrevFrame: Invalid target");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_pop(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_pop(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -1772,7 +1770,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} else { } else {
avm_warn!(self, "RemoveSprite: Source is not a movie clip"); avm_warn!(self, "RemoveSprite: Source is not a movie clip");
} }
Ok(FrameControl::Continue) self.continue_if_base_clip_exists()
} }
fn action_return(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_return(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
@ -2875,4 +2873,15 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
pub fn set_constant_pool(&mut self, constant_pool: GcCell<'gc, Vec<String>>) { pub fn set_constant_pool(&mut self, constant_pool: GcCell<'gc, Vec<String>>) {
self.constant_pool = constant_pool; self.constant_pool = constant_pool;
} }
/// Checks that the clip executing a script still exists.
/// If the clip executing a script is removed during exectuion, return from this activation.
/// Should be called after any action that could potentially destroy a clip (gotos, etc.)
fn continue_if_base_clip_exists(&self) -> Result<FrameControl<'gc>, Error<'gc>> {
if self.base_clip.removed() {
Ok(FrameControl::Return(ReturnType::Explicit(Value::Undefined)))
} else {
Ok(FrameControl::Continue)
}
}
} }