avm2: Throw `VerifyError` for invalid ABC files

This commit is contained in:
relrelb 2022-09-26 13:12:21 +03:00 committed by relrelb
parent a894ec5ca8
commit 95de87ad0a
4 changed files with 31 additions and 15 deletions

View File

@ -9,7 +9,6 @@ use crate::context::UpdateContext;
use crate::string::AvmString;
use fnv::FnvHashMap;
use gc_arena::{Collect, GcCell, MutationContext};
use std::rc::Rc;
use swf::avm2::read::Reader;
use swf::{DoAbc, DoAbcFlag};
@ -287,19 +286,28 @@ impl<'gc> Avm2<'gc> {
do_abc: DoAbc,
domain: Domain<'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 tunit = TranslationUnit::from_abc(abc_file.clone(), domain, context.gc_context);
for i in (0..abc_file.scripts.len()).rev() {
let num_scripts = abc.scripts.len();
let tunit = TranslationUnit::from_abc(abc, domain, context.gc_context);
for i in (0..num_scripts).rev() {
let mut script = tunit.load_script(i as u32, context)?;
if !do_abc.flags.contains(DoAbcFlag::LAZY_INITIALIZE) {
script.globals(context)?;
}
}
Ok(())
}

View File

@ -75,6 +75,17 @@ pub fn reference_error<'gc>(
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>(
activation: &mut Activation<'_, '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> {
fn from(val: crate::tag_utils::Error) -> Error<'gc> {
Error::RustError(val.into())

View File

@ -108,6 +108,7 @@ pub struct SystemClasses<'gc> {
pub referenceerror: ClassObject<'gc>,
pub argumenterror: ClassObject<'gc>,
pub typeerror: ClassObject<'gc>,
pub verifyerror: ClassObject<'gc>,
}
impl<'gc> SystemClasses<'gc> {
@ -183,6 +184,7 @@ impl<'gc> SystemClasses<'gc> {
referenceerror: object,
argumenterror: object,
typeerror: object,
verifyerror: object,
}
}
}
@ -697,6 +699,7 @@ fn load_playerglobal<'gc>(
("", "RangeError", rangeerror),
("", "ReferenceError", referenceerror),
("", "TypeError", typeerror),
("", "VerifyError", verifyerror),
("", "XML", xml),
("", "XMLList", xml_list),
("flash.display", "Scene", scene),

View File

@ -87,7 +87,7 @@ pub struct TranslationUnitData<'gc> {
impl<'gc> TranslationUnit<'gc> {
/// Construct a new `TranslationUnit` for a given ABC file intended to
/// 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 methods = vec![None; abc.methods.len()];
let scripts = vec![None; abc.scripts.len()];
@ -99,7 +99,7 @@ impl<'gc> TranslationUnit<'gc> {
mc,
TranslationUnitData {
domain,
abc,
abc: Rc::new(abc),
classes,
methods,
scripts,