avm2: Enforce max stack & stack depth when pushing/popping from stack

This commit is contained in:
EmperorBale 2022-09-08 16:51:43 -07:00 committed by kmeisthax
parent d46b2c39ca
commit 7a48014d36
3 changed files with 333 additions and 351 deletions

View File

@ -9,6 +9,7 @@ use crate::context::UpdateContext;
use crate::string::AvmString; use crate::string::AvmString;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cmp::Ordering;
use swf::avm2::read::Reader; use swf::avm2::read::Reader;
use swf::{DoAbc, DoAbcFlag}; use swf::{DoAbc, DoAbcFlag};
@ -346,7 +347,11 @@ impl<'gc> Avm2<'gc> {
} }
/// Push a value onto the operand stack. /// Push a value onto the operand stack.
fn push(&mut self, value: impl Into<Value<'gc>>) { fn push(&mut self, value: impl Into<Value<'gc>>, depth: usize, max: usize) {
if self.stack.len() - depth > max {
log::warn!("Avm2::push: Stack overflow");
return;
}
let mut value = value.into(); let mut value = value.into();
if let Value::Object(o) = value { if let Value::Object(o) = value {
if let Some(prim) = o.as_primitive() { if let Some(prim) = o.as_primitive() {
@ -360,11 +365,14 @@ impl<'gc> Avm2<'gc> {
/// Retrieve the top-most value on the operand stack. /// Retrieve the top-most value on the operand stack.
#[allow(clippy::let_and_return)] #[allow(clippy::let_and_return)]
fn pop(&mut self) -> Value<'gc> { fn pop(&mut self, depth: usize) -> Value<'gc> {
let value = self.stack.pop().unwrap_or_else(|| { let value = match self.stack.len().cmp(&depth) {
log::warn!("Avm1::pop: Stack underflow"); Ordering::Equal | Ordering::Less => {
log::warn!("Avm2::pop: Stack underflow");
Value::Undefined Value::Undefined
}); }
Ordering::Greater => self.stack.pop().unwrap_or(Value::Undefined),
};
avm_debug!(self, "Stack pop {}: {:?}", self.stack.len(), value); avm_debug!(self, "Stack pop {}: {:?}", self.stack.len(), value);
@ -388,10 +396,10 @@ impl<'gc> Avm2<'gc> {
value value
} }
fn pop_args(&mut self, arg_count: u32) -> Vec<Value<'gc>> { fn pop_args(&mut self, arg_count: u32, depth: usize) -> Vec<Value<'gc>> {
let mut args = vec![Value::Undefined; arg_count as usize]; let mut args = vec![Value::Undefined; arg_count as usize];
for arg in args.iter_mut().rev() { for arg in args.iter_mut().rev() {
*arg = self.pop(); *arg = self.pop(depth);
} }
args args
} }

File diff suppressed because it is too large Load Diff

View File

@ -225,13 +225,13 @@ impl<'gc> Multiname<'gc> {
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Self, Error<'gc>> { ) -> Result<Self, Error<'gc>> {
let name = if self.has_lazy_name() { let name = if self.has_lazy_name() {
Some(activation.avm2().pop().coerce_to_string(activation)?) Some(activation.pop_stack().coerce_to_string(activation)?)
} else { } else {
self.name self.name
}; };
let ns = if self.has_lazy_ns() { let ns = if self.has_lazy_ns() {
let ns_value = activation.avm2().pop(); let ns_value = activation.pop_stack();
let ns = ns_value.as_namespace()?; let ns = ns_value.as_namespace()?;
NamespaceSet::single(*ns) NamespaceSet::single(*ns)
} else { } else {