avm2: Enforce max stack & stack depth when pushing/popping from stack
This commit is contained in:
parent
d46b2c39ca
commit
7a48014d36
|
@ -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
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue