diff --git a/core/src/avm2/domain.rs b/core/src/avm2/domain.rs index 84ebb0db983f..754de544eb3a 100644 --- a/core/src/avm2/domain.rs +++ b/core/src/avm2/domain.rs @@ -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 @@ -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. /// @@ -62,6 +67,7 @@ impl<'gc> Domain<'gc> { classes: PropertyMap::new(), parent, domain_memory: None, + default_domain_memory: None, }, )) } @@ -82,6 +88,7 @@ impl<'gc> Domain<'gc> { classes: PropertyMap::new(), parent: Some(parent), domain_memory: None, + default_domain_memory: None, }, )); @@ -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() @@ -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 @@ -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(()) } diff --git a/core/src/avm2/globals/flash/system/ApplicationDomain.as b/core/src/avm2/globals/flash/system/ApplicationDomain.as index 21d0f38a289e..ca589e5cb234 100644 --- a/core/src/avm2/globals/flash/system/ApplicationDomain.as +++ b/core/src/avm2/globals/flash/system/ApplicationDomain.as @@ -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; + } + } } diff --git a/core/src/avm2/globals/flash/system/application_domain.rs b/core/src/avm2/globals/flash/system/application_domain.rs index 72613f5b79c2..a4509beaf46b 100644 --- a/core/src/avm2/globals/flash/system/application_domain.rs +++ b/core/src/avm2/globals/flash/system/application_domain.rs @@ -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)?; } } @@ -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) diff --git a/tests/tests/swfs/avm2/domain_memory/Test.as b/tests/tests/swfs/avm2/domain_memory/Test.as new file mode 100644 index 000000000000..b90fe0428e23 --- /dev/null +++ b/tests/tests/swfs/avm2/domain_memory/Test.as @@ -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); + } + + } + } +} diff --git a/tests/tests/swfs/avm2/domain_memory/output.txt b/tests/tests/swfs/avm2/domain_memory/output.txt index 2a3eaf2b49ec..1b261468d460 100644 --- a/tests/tests/swfs/avm2/domain_memory/output.txt +++ b/tests/tests/swfs/avm2/domain_memory/output.txt @@ -1,5 +1,11 @@ +// ApplicationDomain.currentDomain.domainMemory +null +// ApplicationDomain.currentDomain.domainMemory after si8(65, 0) +null // li8(0) after si8(65, 0) 65 +// ApplicationDomain.currentDomain.domainMemory after li8(0) +null // li8(0) after si8(255, 0) 255 // li8(0) after si8(0xFFFFFFFF, 0) @@ -114,3 +120,14 @@ NaN 10 // sxi16(255) 255 +// si8(42, 0) +// ApplicationDomain.currentDomain.domainMemory = bytes +// li8(0) after explicit overwrite +0 +// si8(45, 0) +// ApplicationDomain.currentDomain.domainMemory = null +// li8(0) +42 +// ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH +1024 +Caught error: Error: Error #1504: End of file. diff --git a/tests/tests/swfs/avm2/domain_memory/test.as b/tests/tests/swfs/avm2/domain_memory/test.as deleted file mode 100644 index d5c46ef1a4bd..000000000000 --- a/tests/tests/swfs/avm2/domain_memory/test.as +++ /dev/null @@ -1,180 +0,0 @@ -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 - { - si8(65, 0); - trace("// li8(0) after si8(65, 0)"); - trace(li8(0)); - - 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)); - } - } -} diff --git a/tests/tests/swfs/avm2/domain_memory/test.swf b/tests/tests/swfs/avm2/domain_memory/test.swf index c6f2c52c4070..b162f3939bf3 100644 Binary files a/tests/tests/swfs/avm2/domain_memory/test.swf and b/tests/tests/swfs/avm2/domain_memory/test.swf differ