avm1: Fix variadic arguments

Previously, if the arguments count was greater than the actual
stack size, then a stack underflow occurred which resulted in a
sequence of undefined values. That didn't match Flash's behavior.

Also, this prevents potential huge allocations that hang Ruffle.

In addition, num_args seems like it should use coerce_to_u32
(wraps at 4294967297). This also means that -1 ends up acting like
u32::MAX and would pop all values off of the stack.
This commit is contained in:
relrelb 2021-05-01 15:11:36 +03:00 committed by Mike Welsh
parent e3dc8ff28e
commit 2e0bc78cd6
1 changed files with 8 additions and 4 deletions

View File

@ -804,7 +804,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn action_call_function(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
let fn_name_value = self.context.avm1.pop();
let fn_name = fn_name_value.coerce_to_string(self)?;
let num_args = self.context.avm1.pop().coerce_to_f64(self)? as usize; // TODO(Herschel): max arg count?
let num_args = self.context.avm1.pop().coerce_to_u32(self)? as usize; // TODO(Herschel): max arg count?
let num_args = num_args.min(self.context.avm1.stack.len());
let mut args = Vec::with_capacity(num_args);
for _ in 0..num_args {
args.push(self.context.avm1.pop());
@ -830,7 +831,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn action_call_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
let method = self.context.avm1.pop();
let object_val = self.context.avm1.pop();
let num_args = self.context.avm1.pop().coerce_to_f64(self)? as usize; // TODO(Herschel): max arg count?
let num_args = self.context.avm1.pop().coerce_to_u32(self)? as usize; // TODO(Herschel): max arg count?
let num_args = num_args.min(self.context.avm1.stack.len());
let mut args = Vec::with_capacity(num_args);
for _ in 0..num_args {
args.push(self.context.avm1.pop());
@ -1686,7 +1688,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn action_new_method(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
let method_name = self.context.avm1.pop();
let object_val = self.context.avm1.pop();
let num_args = self.context.avm1.pop().coerce_to_f64(self)? as usize;
let num_args = self.context.avm1.pop().coerce_to_u32(self)? as usize;
let num_args = num_args.min(self.context.avm1.stack.len());
let mut args = Vec::with_capacity(num_args);
for _ in 0..num_args {
args.push(self.context.avm1.pop());
@ -1719,7 +1722,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn action_new_object(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
let fn_name_val = self.context.avm1.pop();
let fn_name = fn_name_val.coerce_to_string(self)?;
let num_args = self.context.avm1.pop().coerce_to_f64(self)? as usize;
let num_args = self.context.avm1.pop().coerce_to_u32(self)? as usize;
let num_args = num_args.min(self.context.avm1.stack.len());
let mut args = Vec::with_capacity(num_args);
for _ in 0..num_args {
args.push(self.context.avm1.pop());