avm2: Use correct error when trying to construct something invalid

This commit is contained in:
Nathan Adams 2023-08-02 10:37:32 +02:00
parent 8bbf8f4ea1
commit 46381d181a
32 changed files with 66 additions and 53 deletions

View File

@ -1252,7 +1252,9 @@ impl<'a, 'gc> Activation<'a, 'gc> {
fn op_call(&mut self, arg_count: u32) -> Result<FrameControl<'gc>, Error<'gc>> {
let args = self.pop_stack_args(arg_count);
let receiver = self.pop_stack();
let function = self.pop_stack().as_callable(self, None, Some(receiver))?;
let function = self
.pop_stack()
.as_callable(self, None, Some(receiver), false)?;
let value = function.call(receiver, &args, self)?;
self.push_stack(value);
@ -1277,7 +1279,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
#[allow(unreachable_code)]
{
let args = self.pop_stack_args(arg_count);
let receiver = self.pop_stack().as_callable(self, None, None)?;
let receiver = self.pop_stack().as_callable(self, None, None, false)?;
let value = receiver.call_method(index.0, &args, self)?;
@ -1321,6 +1323,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
self,
Some(&multiname),
Some(receiver.into()),
false,
)?;
let value = function.call(Value::Null, &args, self)?;
@ -1858,7 +1861,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
fn op_construct(&mut self, arg_count: u32) -> Result<FrameControl<'gc>, Error<'gc>> {
let args = self.pop_stack_args(arg_count);
let ctor = self.pop_stack().as_callable(self, None, None)?;
let ctor = self.pop_stack().as_callable(self, None, None, true)?;
let object = ctor.construct(self, &args)?;

View File

@ -422,7 +422,7 @@ pub fn for_each<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -445,7 +445,7 @@ pub fn map<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut new_array = ArrayStorage::new(0);
let mut iter = ArrayIter::new(activation, this)?;
@ -470,7 +470,7 @@ pub fn filter<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut new_array = ArrayStorage::new(0);
let mut iter = ArrayIter::new(activation, this)?;
@ -499,7 +499,7 @@ pub fn every<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -528,7 +528,7 @@ pub fn some<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -1011,7 +1011,7 @@ pub fn sort<'gc>(
args.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?,
.as_callable(activation, None, None, false)?,
),
SortOptions::from_bits_truncate(
args.get(1)
@ -1022,7 +1022,7 @@ pub fn sort<'gc>(
)
} else {
let arg = args.get(0).cloned().unwrap_or(Value::Undefined);
if let Ok(callable) = arg.as_callable(activation, None, None) {
if let Ok(callable) = arg.as_callable(activation, None, None, false) {
(Some(callable), SortOptions::empty())
} else {
(

View File

@ -23,7 +23,7 @@ pub fn add_frame_script<'gc>(
{
for (frame_id, callable) in args.chunks_exact(2).map(|s| (s[0], s[1])) {
let frame_id = frame_id.coerce_to_u32(activation)? as u16 + 1;
let callable = callable.as_callable(activation, None, None).ok();
let callable = callable.as_callable(activation, None, None, false).ok();
mc.register_frame_script(frame_id, callable, &mut activation.context);
}

View File

@ -39,7 +39,9 @@ pub fn add_event_listener<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let dispatch_list = dispatch_list(activation, this)?;
let event_type = args.get_string(activation, 0)?;
let listener = args.get_value(1).as_callable(activation, None, None)?;
let listener = args
.get_value(1)
.as_callable(activation, None, None, false)?;
let use_capture = args.get_bool(2);
let priority = args.get_i32(activation, 3)?;
@ -62,7 +64,9 @@ pub fn remove_event_listener<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let dispatch_list = dispatch_list(activation, this)?;
let event_type = args.get_string(activation, 0)?;
let listener = args.get_value(1).as_callable(activation, None, None)?;
let listener = args
.get_value(1)
.as_callable(activation, None, None, false)?;
let use_capture = args.get_bool(2);
dispatch_list
@ -152,6 +156,6 @@ pub fn to_string<'gc>(
object_proto
.get_property(&name, activation)?
.as_callable(activation, Some(&name), Some(object_proto.into()))?
.as_callable(activation, Some(&name), Some(object_proto.into()), false)?
.call(this.into(), args, activation)
}

View File

@ -383,7 +383,7 @@ pub fn every<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -412,7 +412,7 @@ pub fn some<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -441,7 +441,7 @@ pub fn filter<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let value_type = this
@ -477,7 +477,7 @@ pub fn for_each<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let mut iter = ArrayIter::new(activation, this)?;
@ -570,7 +570,7 @@ pub fn map<'gc>(
.get(0)
.cloned()
.unwrap_or(Value::Undefined)
.as_callable(activation, None, None)?;
.as_callable(activation, None, None, false)?;
let receiver = args.get(1).cloned().unwrap_or(Value::Null);
let value_type = this
@ -779,7 +779,10 @@ pub fn sort<'gc>(
if let Some(vs) = this.as_vector_storage_mut(activation.context.gc_context) {
let fn_or_options = args.get(0).cloned().unwrap_or(Value::Undefined);
let (compare_fnc, options) = if fn_or_options.as_callable(activation, None, None).is_ok() {
let (compare_fnc, options) = if fn_or_options
.as_callable(activation, None, None, false)
.is_ok()
{
(
Some(fn_or_options.as_object().unwrap()),
SortOptions::empty(),

View File

@ -443,7 +443,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
let result = self
.base()
.get_property_local(multiname, activation)?
.as_callable(activation, Some(multiname), Some(self_val))?;
.as_callable(activation, Some(multiname), Some(self_val), false)?;
result.call(self_val, arguments, activation)
}
@ -466,6 +466,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation,
Some(multiname),
Some(Value::from(self.into())),
false,
)?;
obj.call(Value::from(self.into()), arguments, activation)
@ -512,6 +513,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation,
Some(multiname),
Some(Value::from(self.into())),
false,
)?;
obj.call(Value::from(self.into()), arguments, activation)
@ -884,6 +886,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
activation,
Some(multiname),
Some(Value::from(self.into())),
true,
)?;
ctor.construct(activation, args)

View File

@ -348,7 +348,7 @@ impl<'gc> TObject<'gc> for XmlListObject<'gc> {
}
return method
.as_callable(activation, Some(multiname), Some(self.into()))?
.as_callable(activation, Some(multiname), Some(self.into()), false)?
.call(self.into(), arguments, activation);
}

View File

@ -259,7 +259,7 @@ impl<'gc> TObject<'gc> for XmlObject<'gc> {
}
return method
.as_callable(activation, Some(multiname), Some(self.into()))?
.as_callable(activation, Some(multiname), Some(self.into()), false)?
.call(self.into(), arguments, activation);
}

View File

@ -924,6 +924,7 @@ impl<'gc> Value<'gc> {
activation: &mut Activation<'_, 'gc>,
name: Option<&Multiname<'gc>>,
receiver: Option<Value<'gc>>,
as_constructor: bool,
) -> Result<Object<'gc>, Error<'gc>> {
match self.as_object() {
Some(o) if o.as_class_object().is_some() || o.as_executable().is_some() => Ok(o),
@ -934,16 +935,38 @@ impl<'gc> Value<'gc> {
} else {
"value".into()
};
let msg = if let Some(Value::Object(receiver)) = receiver {
format!(
"Error #1006: {} is not a function of class {}.",
name,
receiver.instance_of_class_name(activation.context.gc_context)
let error = if as_constructor {
if activation.context.swf.version() < 11 {
type_error(
activation,
&format!("Error #1115: {} is not a constructor.", name),
1115,
)
} else {
type_error(
activation,
"Error #1007: Instantiation attempted on a non-constructor.",
1007,
)
}
} else if let Some(Value::Object(receiver)) = receiver {
type_error(
activation,
&format!(
"Error #1006: {} is not a function of class {}.",
name,
receiver.instance_of_class_name(activation.context.gc_context)
),
1006,
)
} else {
format!("Error #1006: {} is not a function.", name)
type_error(
activation,
&format!("Error #1006: {} is not a function.", name),
1006,
)
};
Err(Error::AvmError(type_error(activation, &msg, 1006)?))
Err(Error::AvmError(error?))
}
}
}

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true