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

core: Fix endless loop in process_swf5_references #9885

Merged
merged 2 commits into from
Mar 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions core/src/avm1/object_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ impl<'gc> MovieClipReference<'gc> {
),
})
} else if activation.swf_version() <= 5 {
let display_object = Self::process_swf5_references(activation, display_object);
let display_object = Self::process_swf5_references(activation, display_object)?;

let stage_object = display_object
.object()
.coerce_to_object(activation)
Expand All @@ -105,16 +106,20 @@ impl<'gc> MovieClipReference<'gc> {
fn process_swf5_references(
activation: &mut Activation<'_, 'gc>,
mut display_object: DisplayObject<'gc>,
) -> DisplayObject<'gc> {
) -> Option<DisplayObject<'gc>> {
// In swfv5 paths resolve to the first MovieClip parent if the target isn't a movieclip
if activation.swf_version() <= 5 {
while display_object.as_movie_clip().is_none() {
if let Some(p) = display_object.avm1_parent() {
display_object = p;
} else {
// Somehow we have gotten an object that has no MovieClip up the chain
return None;
}
}
}
display_object

Some(display_object)
}

/// Resolve this reference to an object
Expand All @@ -131,7 +136,7 @@ impl<'gc> MovieClipReference<'gc> {
// We have to fallback to manual path-walking if the object is removed
if !mc.read().display_object.avm1_removed() {
let display_object = mc.read().display_object;
let display_object = Self::process_swf5_references(activation, display_object);
let display_object = Self::process_swf5_references(activation, display_object)?;

// Note that there is a bug here but this *is* how it works in Flash:
// If we are using the cached DisplayObject, we return it's path, which can be changed by modifying `_name`
Expand Down Expand Up @@ -175,7 +180,7 @@ impl<'gc> MovieClipReference<'gc> {
}

if let Some(start) = start {
let display_object = Self::process_swf5_references(activation, start);
let display_object = Self::process_swf5_references(activation, start)?;

Some((
false,
Expand Down
2 changes: 2 additions & 0 deletions tests/tests/swfs/avm1/issue_9885/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
foo
foo
Binary file added tests/tests/swfs/avm1/issue_9885/test.fla
Binary file not shown.
Binary file added tests/tests/swfs/avm1/issue_9885/test.swf
Binary file not shown.
1 change: 1 addition & 0 deletions tests/tests/swfs/avm1/issue_9885/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
num_frames = 2