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

avm2: Fix handling of default domain memory #12308

Merged
merged 2 commits into from
Jul 26, 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
59 changes: 51 additions & 8 deletions core/src/avm2/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_wstr::WStr;

use super::class::Class;
use super::error::error;
use super::string::AvmString;

/// Represents a set of scripts and movies that share traits across different
Expand Down Expand Up @@ -40,8 +41,12 @@ struct DomainData<'gc> {
/// player globals setup (we need a global domain to put globals into, but
/// that domain needs the bytearray global)
pub domain_memory: Option<ByteArrayObject<'gc>>,

pub default_domain_memory: Option<ByteArrayObject<'gc>>,
}

const MIN_DOMAIN_MEMORY_LENGTH: usize = 1024;

impl<'gc> Domain<'gc> {
/// Create a new domain with no parent.
///
Expand All @@ -62,6 +67,7 @@ impl<'gc> Domain<'gc> {
classes: PropertyMap::new(),
parent,
domain_memory: None,
default_domain_memory: None,
},
))
}
Expand All @@ -82,6 +88,7 @@ impl<'gc> Domain<'gc> {
classes: PropertyMap::new(),
parent: Some(parent),
domain_memory: None,
default_domain_memory: None,
},
));

Expand Down Expand Up @@ -294,6 +301,15 @@ impl<'gc> Domain<'gc> {
self.0.write(mc).classes.insert(class.read().name(), class);
}

pub fn is_default_domain_memory(&self) -> bool {
let read = self.0.read();
read.domain_memory.expect("Missing domain memory").as_ptr()
== read
.default_domain_memory
.expect("Missing default domain memory")
.as_ptr()
}

pub fn domain_memory(&self) -> ByteArrayObject<'gc> {
self.0
.read()
Expand All @@ -303,10 +319,26 @@ impl<'gc> Domain<'gc> {

pub fn set_domain_memory(
&self,
mc: MutationContext<'gc, '_>,
domain_memory: ByteArrayObject<'gc>,
) {
self.0.write(mc).domain_memory = Some(domain_memory)
activation: &mut Activation<'_, 'gc>,
domain_memory: Option<ByteArrayObject<'gc>>,
) -> Result<(), Error<'gc>> {
let mut write = self.0.write(activation.context.gc_context);
let memory = if let Some(domain_memory) = domain_memory {
if domain_memory.storage().len() < MIN_DOMAIN_MEMORY_LENGTH {
return Err(Error::AvmError(error(
activation,
"Error #1504: End of file.",
1504,
)?));
}
domain_memory
} else {
write
.default_domain_memory
.expect("Default domain memory not initialized")
};
write.domain_memory = Some(memory);
Ok(())
}

/// Allocate the default domain memory for this domain, if it does not
Expand All @@ -325,12 +357,23 @@ impl<'gc> Domain<'gc> {
domain_memory
.as_bytearray_mut(activation.context.gc_context)
.unwrap()
.set_length(1024);
.set_length(MIN_DOMAIN_MEMORY_LENGTH);

let mut write = self.0.write(activation.context.gc_context);
write
.domain_memory
.get_or_insert(domain_memory.as_bytearray_object().unwrap());

assert!(
write.domain_memory.is_none(),
"Already initialized domain memory!"
);
assert!(
write.default_domain_memory.is_none(),
"Already initialized domain memory!"
);

let bytearray = domain_memory.as_bytearray_object().unwrap();

write.domain_memory = Some(bytearray);
write.default_domain_memory = Some(bytearray);

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions core/src/avm2/globals/flash/system/ApplicationDomain.as
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ package flash.system {
public native function hasDefinition(name:String):Boolean;

public native function getQualifiedDefinitionNames():Vector.<String>;

public static function get MIN_DOMAIN_MEMORY_LENGTH():uint {
return 1024;
}

}
}
19 changes: 12 additions & 7 deletions core/src/avm2/globals/flash/system/application_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,12 @@ pub fn set_domain_memory<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(Value::Object(arg)) = args.get(0) {
if let Some(bytearray_obj) = arg.as_bytearray_object() {
if let Some(appdomain) = this.as_application_domain() {
appdomain.set_domain_memory(activation.context.gc_context, bytearray_obj);
}
if let Some(appdomain) = this.as_application_domain() {
let obj = args.try_get_object(activation, 0);
if let Some(obj) = obj {
appdomain.set_domain_memory(activation, Some(obj.as_bytearray_object().unwrap()))?;
} else {
appdomain.set_domain_memory(activation, None)?;
}
}

Expand All @@ -158,8 +159,12 @@ pub fn get_domain_memory<'gc>(
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(appdomain) = this.as_application_domain() {
let bytearray_object: Object<'gc> = appdomain.domain_memory().into();
return Ok(bytearray_object.into());
if appdomain.is_default_domain_memory() {
return Ok(Value::Null);
} else {
let bytearray_object: Object<'gc> = appdomain.domain_memory().into();
return Ok(bytearray_object.into());
}
}

Ok(Value::Undefined)
Expand Down
218 changes: 218 additions & 0 deletions tests/tests/swfs/avm2/domain_memory/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package {
import flash.utils.Endian;
import avm2.intrinsics.memory.si8;
import avm2.intrinsics.memory.si16;
import avm2.intrinsics.memory.si32;
import avm2.intrinsics.memory.sf32;
import avm2.intrinsics.memory.sf64;
import avm2.intrinsics.memory.li8;
import avm2.intrinsics.memory.li16;
import avm2.intrinsics.memory.li32;
import avm2.intrinsics.memory.lf32;
import avm2.intrinsics.memory.lf64;
import avm2.intrinsics.memory.sxi1;
import avm2.intrinsics.memory.sxi8;
import avm2.intrinsics.memory.sxi16;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.display.Sprite;

public class Test extends Sprite {
public function Test() {
init();
}

private function init():void {
trace("// ApplicationDomain.currentDomain.domainMemory");
trace(ApplicationDomain.currentDomain.domainMemory);
si8(65, 0);

trace("// ApplicationDomain.currentDomain.domainMemory after si8(65, 0)");
trace(ApplicationDomain.currentDomain.domainMemory);

trace("// li8(0) after si8(65, 0)");
trace(li8(0));

trace("// ApplicationDomain.currentDomain.domainMemory after li8(0)");
trace(ApplicationDomain.currentDomain.domainMemory);

si8(255, 0);
trace("// li8(0) after si8(255, 0)");
trace(li8(0));

si8(0xFFFFFFFF, 0);
trace("// li8(0) after si8(0xFFFFFFFF, 0)");
trace(li8(0));
trace("// li8(1) after si8(0xFFFFFFFF, 0)");
trace(li8(1));
trace("// li8(1) after si8(0xFFFFFFFF, 0)");
trace(li8(2));
trace("// li8(1) after si8(0xFFFFFFFF, 0)");
trace(li8(3));

si16(256, 0);
trace("// li8(0) after si16(256, 0)");
trace(li8(0));
trace("// li8(1) after si16(256, 0)");
trace(li8(1));
trace("// li16(0) after si16(256, 0)");
trace(li16(0));

si16(0xFFFF, 0);
trace("// li8(0) after si16(0xFFFF, 0)");
trace(li8(0));
trace("// li8(1) after si16(0xFFFF, 0)");
trace(li8(1));
trace("// li16(0) after si16(0xFFFF, 0)");
trace(li16(0));

si16(0xFFFFFFFF, 0);
trace("// li8(0) after si16(0xFFFFFFFF, 0)");
trace(li8(0));
trace("// li8(1) after si16(0xFFFFFFFF, 0)");
trace(li8(1));
trace("// li8(1) after si16(0xFFFFFFFF, 0)");
trace(li8(2));
trace("// li8(1) after si16(0xFFFFFFFF, 0)");
trace(li8(3));

si32(0xFFFFFFFF, 0);
trace("// li8(0) after si32(0xFFFFFFFF, 0)");
trace(li8(0));
trace("// li8(1) after si32(0xFFFFFFFF, 0)");
trace(li8(1));
trace("// li8(2) after si32(0xFFFFFFFF, 0)");
trace(li8(2));
trace("// li8(3) after si32(0xFFFFFFFF, 0)");
trace(li8(3));
trace("// li32(0) after si32(0xFFFFFFFF, 0)");
trace(li32(0));

sf32(0xFFFFFFFF, 0);
trace("// li8(0) after sf32(0xFFFFFFFF, 0)");
trace(li8(0));
trace("// li8(1) after sf32(0xFFFFFFFF, 0)");
trace(li8(1));
trace("// li8(2) after sf32(0xFFFFFFFF, 0)");
trace(li8(2));
trace("// li8(3) after sf32(0xFFFFFFFF, 0)");
trace(li8(3));
trace("// li32(0) after sf32(0xFFFFFFFF, 0)");
trace(li32(0));
trace("// lf32(0) after sf32(0xFFFFFFFF, 0)");
trace(lf32(0));

sf32(1234.7654321, 0);
trace("// li8(0) after sf32(1234.7654321, 0)");
trace(li8(0));
trace("// li8(1) after sf32(1234.7654321, 0)");
trace(li8(1));
trace("// li8(2) after sf32(1234.7654321, 0)");
trace(li8(2));
trace("// li8(3) after sf32(1234.7654321, 0)");
trace(li8(3));
trace("// li32(0) after sf32(1234.7654321, 0)");
trace(li32(0));
trace("// lf32(0) after sf32(1234.7654321, 0)");
trace(lf32(0));

sf64(999999.9999999999, 0);
trace("// li8(0) after sf64(999999.9999999999, 0)");
trace(li8(0));
trace("// li8(1) after sf64(999999.9999999999, 0)");
trace(li8(1));
trace("// li8(2) after sf64(999999.9999999999, 0)");
trace(li8(2));
trace("// li8(3) after sf64(999999.9999999999, 0)");
trace(li8(3));
trace("// li8(4) after sf64(999999.9999999999, 0)");
trace(li8(4));
trace("// li8(5) after sf64(999999.9999999999, 0)");
trace(li8(5));
trace("// li8(6) after sf64(999999.9999999999, 0)");
trace(li8(6));
trace("// li8(7) after sf64(999999.9999999999, 0)");
trace(li8(7));

trace("// li32(0) after sf64(999999.9999999999, 0)");
trace(li32(0));
trace("// li32(4) after sf64(999999.9999999999, 0)");
trace(li32(4));
trace("// lf32(0) after sf64(999999.9999999999, 0)");
trace(lf32(0));
trace("// lf32(4) after sf64(999999.9999999999, 0)");
trace(lf32(0));
trace("// lf64(0) after sf64(999999.9999999999, 0)");
trace(lf64(0));

trace("// sxi1(0)");
trace(sxi1(0));

trace("// sxi1(1)");
trace(sxi1(1));

trace("// sxi1(10)");
trace(sxi1(10));

trace("// sxi1(255)");
trace(sxi1(255));

trace("// sxi8(0)");
trace(sxi8(0));

trace("// sxi8(1)");
trace(sxi8(1));

trace("// sxi8(10)");
trace(sxi8(10));

trace("// sxi8(255)");
trace(sxi8(255));

trace("// sxi16(0)");
trace(sxi16(0));

trace("// sxi16(1)");
trace(sxi16(1));

trace("// sxi16(10)");
trace(sxi16(10));

trace("// sxi16(255)");
trace(sxi16(255));

trace("// si8(42, 0)");
si8(42, 0);

var bytes = new ByteArray();
bytes.length = 1024;
trace("// ApplicationDomain.currentDomain.domainMemory = bytes");
ApplicationDomain.currentDomain.domainMemory = bytes;

trace("// li8(0) after explicit overwrite");
trace(li8(0));

trace("// si8(45, 0)");
si8(45, 0);

trace("// ApplicationDomain.currentDomain.domainMemory = null");
ApplicationDomain.currentDomain.domainMemory = null;

trace("// li8(0)");
trace(li8(0));

trace("// ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH")
trace(ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH)

var bytes = new ByteArray();
bytes.length = ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH - 1;
try {
ApplicationDomain.currentDomain.domainMemory = bytes;
trace("FAILED - write should have thrown an error")
} catch (e) {
trace("Caught error: " + e);
}

}
}
}
Loading