From 427b2bf17a0d3a9ae77635a901cf8d7f749f6cd0 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Thu, 4 Nov 2021 20:53:18 -0400 Subject: [PATCH] avm2: Implement `Proxy.deleteproperty` --- core/src/avm2/activation.rs | 6 +-- core/src/avm2/object.rs | 28 ++++++++++---- core/src/avm2/object/proxy_object.rs | 35 ++++++++++++++++++ .../swfs/avm2/proxy_deleteproperty/Test.as | 10 ++++- .../swfs/avm2/proxy_deleteproperty/output.txt | 9 +++++ .../swfs/avm2/proxy_deleteproperty/test.swf | Bin 1399 -> 1477 bytes 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index d2153323a..8cadbc083 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -1405,9 +1405,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { (multiname, object) }; - self.context - .avm2 - .push(object.delete_property(self.context.gc_context, &multiname)?); + let did_delete = object.delete_property(self, &multiname)?; + + self.context.avm2.push(did_delete); Ok(FrameControl::Continue) } diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index d325b764c..2ed1bc206 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -687,22 +687,36 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy Ok(base.delete_property(name)) } + /// Delete a property that does not exist. + /// + /// By default, undefined property deletion succeeds for dynamic classes, + /// and fails for sealed ones. Objects that have particular alternative + /// behavior for undefined values may substitute their own implementation + /// here without disturbing the rest of `deleteproperty`'s implementation. + fn delete_property_undef( + &self, + _activation: &mut Activation<'_, 'gc, '_>, + _multiname: &Multiname<'gc>, + ) -> Result { + // Unknown properties on a dynamic class delete successfully. + return Ok(!self + .instance_of_class_definition() + .map(|c| c.read().is_sealed()) + .unwrap_or(false)); + } + /// Delete a named property from the object. /// /// Returns false if the property cannot be deleted. fn delete_property( &self, - gc_context: MutationContext<'gc, '_>, + activation: &mut Activation<'_, 'gc, '_>, multiname: &Multiname<'gc>, ) -> Result { let name = self.resolve_multiname(multiname)?; if name.is_none() { - // Unknown properties on a dynamic class delete successfully. - return Ok(!self - .instance_of_class_definition() - .map(|c| c.read().is_sealed()) - .unwrap_or(false)); + return self.delete_property_undef(activation, multiname); } //At this point, the name should be known. @@ -732,7 +746,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy } } - self.delete_property_local(gc_context, &name) + self.delete_property_local(activation.context.gc_context, &name) } /// Retrieve the `__proto__` of a given object. diff --git a/core/src/avm2/object/proxy_object.rs b/core/src/avm2/object/proxy_object.rs index 4490cb19e..011513efa 100644 --- a/core/src/avm2/object/proxy_object.rs +++ b/core/src/avm2/object/proxy_object.rs @@ -172,4 +172,39 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> { ) .into()) } + + fn delete_property_undef( + &self, + activation: &mut Activation<'_, 'gc, '_>, + multiname: &Multiname<'gc>, + ) -> Result { + for namespace in multiname.namespace_set() { + if let Some(local_name) = multiname.local_name() { + if namespace.is_any() || namespace.is_public() || namespace.is_namespace() { + let qname = QNameObject::from_qname( + activation, + QName::new(namespace.clone(), local_name), + )?; + + return Ok(self + .call_property( + &QName::new( + Namespace::Namespace(NS_FLASH_PROXY.into()), + "deleteProperty", + ) + .into(), + &[qname.into()], + activation, + )? + .coerce_to_boolean()); + } + } + } + + // Unknown properties on a dynamic class delete successfully. + return Ok(!self + .instance_of_class_definition() + .map(|c| c.read().is_sealed()) + .unwrap_or(false)); + } } diff --git a/tests/tests/swfs/avm2/proxy_deleteproperty/Test.as b/tests/tests/swfs/avm2/proxy_deleteproperty/Test.as index 4f5a33690..8d5dbcb3c 100644 --- a/tests/tests/swfs/avm2/proxy_deleteproperty/Test.as +++ b/tests/tests/swfs/avm2/proxy_deleteproperty/Test.as @@ -17,6 +17,11 @@ dynamic class TestProxy extends Proxy { trace("///name.uri"); trace(name.uri); + + if (name.localName === "crazy_return") { + trace("///returning non-bool value"); + return "This isn't a bool at all"; + } } else if (name is String) { trace("///type of name is String"); } else { @@ -71,4 +76,7 @@ trace("///delete p.proxy_var"); trace(delete p.proxy_var); trace("///delete p.proxy_fn"); -trace(delete p.proxy_fn); \ No newline at end of file +trace(delete p.proxy_fn); + +trace("///delete p.crazy_return"); +trace(delete p.crazy_return); \ No newline at end of file diff --git a/tests/tests/swfs/avm2/proxy_deleteproperty/output.txt b/tests/tests/swfs/avm2/proxy_deleteproperty/output.txt index 4586c7927..e3037eb42 100644 --- a/tests/tests/swfs/avm2/proxy_deleteproperty/output.txt +++ b/tests/tests/swfs/avm2/proxy_deleteproperty/output.txt @@ -57,3 +57,12 @@ proxy_fn ///name.uri true +///delete p.crazy_return +///attempted to delete property: crazy_return +///type of name is QName +///name.localName +crazy_return +///name.uri + +///returning non-bool value +true diff --git a/tests/tests/swfs/avm2/proxy_deleteproperty/test.swf b/tests/tests/swfs/avm2/proxy_deleteproperty/test.swf index da98fc7711378e0ec7a1e47d2b683821bd6795bc..ecbcafb78aa40d2f9c6031f1e288aa369ab39283 100644 GIT binary patch literal 1477 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