avm2: Throw `VerifyError` for invalid ABC files
This commit is contained in:
parent
a894ec5ca8
commit
95de87ad0a
|
@ -9,7 +9,6 @@ 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::rc::Rc;
|
|
||||||
use swf::avm2::read::Reader;
|
use swf::avm2::read::Reader;
|
||||||
use swf::{DoAbc, DoAbcFlag};
|
use swf::{DoAbc, DoAbcFlag};
|
||||||
|
|
||||||
|
@ -287,19 +286,28 @@ impl<'gc> Avm2<'gc> {
|
||||||
do_abc: DoAbc,
|
do_abc: DoAbc,
|
||||||
domain: Domain<'gc>,
|
domain: Domain<'gc>,
|
||||||
) -> Result<(), Error<'gc>> {
|
) -> Result<(), Error<'gc>> {
|
||||||
let mut read = Reader::new(do_abc.data);
|
let mut reader = Reader::new(do_abc.data);
|
||||||
|
let abc = match reader.read() {
|
||||||
|
Ok(abc) => abc,
|
||||||
|
Err(_) => {
|
||||||
|
let mut activation = Activation::from_nothing(context.reborrow());
|
||||||
|
return Err(Error::AvmError(crate::avm2::error::verify_error(
|
||||||
|
&mut activation,
|
||||||
|
"Error #1107: The ABC data is corrupt, attempt to read out of bounds.",
|
||||||
|
1107,
|
||||||
|
)?));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let abc_file = Rc::new(read.read()?);
|
let num_scripts = abc.scripts.len();
|
||||||
let tunit = TranslationUnit::from_abc(abc_file.clone(), domain, context.gc_context);
|
let tunit = TranslationUnit::from_abc(abc, domain, context.gc_context);
|
||||||
|
for i in (0..num_scripts).rev() {
|
||||||
for i in (0..abc_file.scripts.len()).rev() {
|
|
||||||
let mut script = tunit.load_script(i as u32, context)?;
|
let mut script = tunit.load_script(i as u32, context)?;
|
||||||
|
|
||||||
if !do_abc.flags.contains(DoAbcFlag::LAZY_INITIALIZE) {
|
if !do_abc.flags.contains(DoAbcFlag::LAZY_INITIALIZE) {
|
||||||
script.globals(context)?;
|
script.globals(context)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,17 @@ pub fn reference_error<'gc>(
|
||||||
error_constructor(activation, class, message, code)
|
error_constructor(activation, class, message, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
#[cold]
|
||||||
|
pub fn verify_error<'gc>(
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
message: &str,
|
||||||
|
code: u32,
|
||||||
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
|
let class = activation.avm2().classes().verifyerror;
|
||||||
|
error_constructor(activation, class, message, code)
|
||||||
|
}
|
||||||
|
|
||||||
fn error_constructor<'gc>(
|
fn error_constructor<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
class: ClassObject<'gc>,
|
class: ClassObject<'gc>,
|
||||||
|
@ -122,12 +133,6 @@ impl<'gc> From<std::fmt::Error> for Error<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> From<swf::error::Error> for Error<'gc> {
|
|
||||||
fn from(val: swf::error::Error) -> Error<'gc> {
|
|
||||||
Error::RustError(val.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc> From<crate::tag_utils::Error> for Error<'gc> {
|
impl<'gc> From<crate::tag_utils::Error> for Error<'gc> {
|
||||||
fn from(val: crate::tag_utils::Error) -> Error<'gc> {
|
fn from(val: crate::tag_utils::Error) -> Error<'gc> {
|
||||||
Error::RustError(val.into())
|
Error::RustError(val.into())
|
||||||
|
|
|
@ -108,6 +108,7 @@ pub struct SystemClasses<'gc> {
|
||||||
pub referenceerror: ClassObject<'gc>,
|
pub referenceerror: ClassObject<'gc>,
|
||||||
pub argumenterror: ClassObject<'gc>,
|
pub argumenterror: ClassObject<'gc>,
|
||||||
pub typeerror: ClassObject<'gc>,
|
pub typeerror: ClassObject<'gc>,
|
||||||
|
pub verifyerror: ClassObject<'gc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> SystemClasses<'gc> {
|
impl<'gc> SystemClasses<'gc> {
|
||||||
|
@ -183,6 +184,7 @@ impl<'gc> SystemClasses<'gc> {
|
||||||
referenceerror: object,
|
referenceerror: object,
|
||||||
argumenterror: object,
|
argumenterror: object,
|
||||||
typeerror: object,
|
typeerror: object,
|
||||||
|
verifyerror: object,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,6 +699,7 @@ fn load_playerglobal<'gc>(
|
||||||
("", "RangeError", rangeerror),
|
("", "RangeError", rangeerror),
|
||||||
("", "ReferenceError", referenceerror),
|
("", "ReferenceError", referenceerror),
|
||||||
("", "TypeError", typeerror),
|
("", "TypeError", typeerror),
|
||||||
|
("", "VerifyError", verifyerror),
|
||||||
("", "XML", xml),
|
("", "XML", xml),
|
||||||
("", "XMLList", xml_list),
|
("", "XMLList", xml_list),
|
||||||
("flash.display", "Scene", scene),
|
("flash.display", "Scene", scene),
|
||||||
|
|
|
@ -87,7 +87,7 @@ pub struct TranslationUnitData<'gc> {
|
||||||
impl<'gc> TranslationUnit<'gc> {
|
impl<'gc> TranslationUnit<'gc> {
|
||||||
/// Construct a new `TranslationUnit` for a given ABC file intended to
|
/// Construct a new `TranslationUnit` for a given ABC file intended to
|
||||||
/// execute within a particular domain.
|
/// execute within a particular domain.
|
||||||
pub fn from_abc(abc: Rc<AbcFile>, domain: Domain<'gc>, mc: MutationContext<'gc, '_>) -> Self {
|
pub fn from_abc(abc: AbcFile, domain: Domain<'gc>, mc: MutationContext<'gc, '_>) -> Self {
|
||||||
let classes = vec![None; abc.classes.len()];
|
let classes = vec![None; abc.classes.len()];
|
||||||
let methods = vec![None; abc.methods.len()];
|
let methods = vec![None; abc.methods.len()];
|
||||||
let scripts = vec![None; abc.scripts.len()];
|
let scripts = vec![None; abc.scripts.len()];
|
||||||
|
@ -99,7 +99,7 @@ impl<'gc> TranslationUnit<'gc> {
|
||||||
mc,
|
mc,
|
||||||
TranslationUnitData {
|
TranslationUnitData {
|
||||||
domain,
|
domain,
|
||||||
abc,
|
abc: Rc::new(abc),
|
||||||
classes,
|
classes,
|
||||||
methods,
|
methods,
|
||||||
scripts,
|
scripts,
|
||||||
|
|
Loading…
Reference in New Issue