Skip to content

Commit ba41b1c

Browse files
avm2: Panic when calling set_dynamic_property methods on a sealed object
1 parent 6e42e8b commit ba41b1c

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

core/src/avm2/object.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
247247
/// Get a dynamic property on this Object by name. This is like
248248
/// `get_property_local`, but it skips dynamic-dispatch TObject logic
249249
/// and always gets a dynamic property on the base ScriptObject. If the
250-
/// property does not exist on the ScriptObject, this returns `None`.
250+
/// object is sealed, or the dynamic property does not exist on the
251+
/// ScriptObject, this returns `None`.
251252
#[no_dynamic]
252253
fn get_dynamic_property(self, local_name: AvmString<'gc>) -> Option<Value<'gc>> {
253254
use crate::avm2::object::script_object::maybe_int_property;
@@ -285,6 +286,14 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
285286
/// Set a dynamic property on this Object by name. This is like
286287
/// `set_property_local`, but it skips dynamic-dispatch TObject logic
287288
/// and always sets a dynamic property on the base ScriptObject.
289+
///
290+
/// Note that calling this method on a non-dynamic (sealed) object will
291+
/// panic, as sealed objects cannot have dynamic properties set on them.
292+
///
293+
/// Additionally, if the vtable of the object has the property `local_name`
294+
/// in it, this method will still declare a dynamic property on the object
295+
/// with the same name, so take care to only call this method on objects
296+
/// that are known to not have the property `local_name` in their vtable.
288297
#[no_dynamic]
289298
fn set_dynamic_property(
290299
self,
@@ -294,10 +303,13 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
294303
) {
295304
use crate::avm2::object::script_object::maybe_int_property;
296305

306+
let base = self.base();
307+
assert!(!base.is_sealed());
308+
297309
// See the comment in ScriptObjectWrapper::set_property_local
298310
let key = maybe_int_property(local_name);
299311

300-
self.base().values_mut(mc).insert(key, value);
312+
base.values_mut(mc).insert(key, value);
301313
}
302314

303315
/// Purely an optimization for "array-like" access. This should return
@@ -368,12 +380,18 @@ pub trait TObject<'gc>: 'gc + Collect<'gc> + Debug + Into<Object<'gc>> + Clone +
368380
/// Delete a dynamic property on this Object by name. This is like
369381
/// `delete_property_local`, but it skips dynamic-dispatch TObject logic
370382
/// and always tries to delete a dynamic property on the base ScriptObject.
383+
///
384+
/// This method will panic when called on a non-dynamic (sealed) object, as
385+
/// sealed objects don't have dynamic properties to delete anyway.
371386
#[no_dynamic]
372387
fn delete_dynamic_property(self, name: AvmString<'gc>, mc: &Mutation<'gc>) {
373388
use crate::avm2::object::script_object::maybe_int_property;
374389

390+
let base = self.base();
391+
assert!(!base.is_sealed());
392+
375393
let key = maybe_int_property(name);
376-
self.base().values_mut(mc).remove(&key);
394+
base.values_mut(mc).remove(&key);
377395
}
378396

379397
/// Retrieve a slot by its index.

0 commit comments

Comments
 (0)