From 5d89d4ed857a3a0ff34cbcd6b72ce764c300c159 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 7 Jul 2020 21:28:24 -0400 Subject: [PATCH] Allow methods to not hold a body. Interface methods are specifically not allowed to be called: as a result, they don't get a method body. Existing code assumed a 1:1 relationship between methods and bodies, which causes spurious errors. --- core/src/avm2/activation.rs | 21 +++++++++++++++------ core/src/avm2/function.rs | 2 +- core/src/avm2/method.rs | 29 +++++++++++++++++++---------- core/src/avm2/object.rs | 2 +- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index e936a06c1..ac2073707 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -139,7 +139,10 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { ) -> Result { let method = script.read().init().into_bytecode()?; let scope = Some(Scope::push_scope(None, global, context.gc_context)); - let num_locals = method.body().num_locals; + let body: Result<_, Error> = method + .body() + .ok_or_else(|| "Cannot execute non-native method (for script) without body".into()); + let num_locals = body?.num_locals; let local_registers = GcCell::allocate(context.gc_context, RegisterSet::new(num_locals + 1)); @@ -171,8 +174,11 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { this: Option>, arguments: &[Value<'gc>], base_proto: Option>, - ) -> Self { - let num_locals = method.body().num_locals; + ) -> Result { + let body: Result<_, Error> = method + .body() + .ok_or_else(|| "Cannot execute non-native method without body".into()); + let num_locals = body?.num_locals; let num_declared_arguments = method.method().params.len() as u32; let local_registers = GcCell::allocate( context.gc_context, @@ -191,7 +197,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { } } - Self { + Ok(Self { avm2, this, arguments: None, @@ -201,7 +207,7 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { local_scope: ScriptObject::bare_object(context.gc_context), scope, base_proto, - } + }) } /// Execute a script initializer. @@ -380,7 +386,10 @@ impl<'a, 'gc: 'a> Activation<'a, 'gc> { method: Gc<'gc, BytecodeMethod<'gc>>, context: &mut UpdateContext<'_, 'gc, '_>, ) -> Result, Error> { - let mut read = Reader::new(Cursor::new(method.body().code.as_ref())); + let body: Result<_, Error> = method + .body() + .ok_or_else(|| "Cannot execute non-native method without body".into()); + let mut read = Reader::new(Cursor::new(body?.code.as_ref())); loop { let result = self.do_next_opcode(method, context, &mut read); diff --git a/core/src/avm2/function.rs b/core/src/avm2/function.rs index 75e43efbc..62e8be5b5 100644 --- a/core/src/avm2/function.rs +++ b/core/src/avm2/function.rs @@ -107,7 +107,7 @@ impl<'gc> Executable<'gc> { reciever, arguments, base_proto, - ); + )?; activation.run_actions(bm.method, context) } diff --git a/core/src/avm2/method.rs b/core/src/avm2/method.rs index 3d9e49d25..1ca6cbb5a 100644 --- a/core/src/avm2/method.rs +++ b/core/src/avm2/method.rs @@ -50,7 +50,7 @@ pub struct BytecodeMethod<'gc> { pub abc_method: u32, /// The ABC method body this function uses. - pub abc_method_body: u32, + pub abc_method_body: Option, } impl<'gc> BytecodeMethod<'gc> { @@ -74,14 +74,22 @@ impl<'gc> BytecodeMethod<'gc> { txunit, abc: CollectWrapper(txunit.abc()), abc_method: abc_method.0, - abc_method_body: index as u32, + abc_method_body: Some(index as u32), }, )); } } } - None + Some(Gc::allocate( + mc, + Self { + txunit, + abc: CollectWrapper(txunit.abc()), + abc_method: abc_method.0, + abc_method_body: None, + }, + )) } /// Get the underlying ABC file. @@ -101,13 +109,14 @@ impl<'gc> BytecodeMethod<'gc> { } /// Get a reference to the ABC method body entry this refers to. - pub fn body(&self) -> &AbcMethodBody { - &self - .abc - .0 - .method_bodies - .get(self.abc_method_body as usize) - .unwrap() + /// + /// Some methods do not have bodies; this returns `None` in that case. + pub fn body(&self) -> Option<&AbcMethodBody> { + if let Some(abc_method_body) = self.abc_method_body { + self.abc.0.method_bodies.get(abc_method_body as usize) + } else { + None + } } } diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 056da591d..4ecc5fd38 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -427,7 +427,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy avm_debug!( "Installing trait {:?} of kind {:?}", trait_name, - trait_entry.kind + trait_entry.kind() ); match trait_entry.kind() {