Boa: Altering vital properties of builtins

Created on 7 Aug 2020  路  9Comments  路  Source: boa-dev/boa

Describe the bug
Some internal properties (which must not be allowed to set by the user) are being set.

Ex:

>> Object.prototype = 12
12
>> Object.prototype
>> new Object()
thread 'main' panicked at 'assertion failed: prototype.is_null() || prototype.is_object()', boa/src/builtins/object/mod.rs:433:9

Expected behavior
Such things must not alter the contents of a property. For example, in the case of Object.prototype, the spec tells the property must be NOT (writable, enumerable, configurable). But it looks like the property is being set using the insert_field method where the attributes of the property are (WRITABLE, ENUMERABLE, CONFIGURABLE).

bug help wanted discussion execution

All 9 comments

I think one solution is to add a new method on objects: insert_internal_property (or any other name) which will insert a new property with attributes (READONLY, NON_ENUMERABLE, PERMANENT). Then we must replace the calls to insert_field at various places by insert_internal_property.

@HalidOdat could you share your thoughts about this?

I think one solution is to add a new method on objects: insert_internal_property (or any other name) which will insert a new property with attributes (READONLY, NON_ENUMERABLE, PERMANENT). Then we must replace the calls to insert_field at various places by insert_internal_property.

@HalidOdat could you share your thoughts about this?

Hmmm. I would rename insert_propertyto insert and add insert_property with the following signiture:

#[inline]
pub(crate) fn insert_property<K>(&mut self, key: K value: V, attribute: Attribute) -> Option<Property>
where
    Key: Into<PropertyKey>,
    V: Into<Value>,
{
    self.insert(key.into(), Property::data_descriptor(value.into(), attribute))
}

This way forces us to change all calls to add the attributes:

object.insert_property("length", 10, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT);

And we remove the insert_field

What do you think @54k1 ?

pub(crate) fn insert_property<K>(&mut self, key: K value: V, attribute: Attribute) -> Option<Property>

Actually I do not understand why insert_property must return an Option.

This way forces us to change all calls to add the attributes:

Yes, this would be better. However, I think it'll also be handy to have a function to insert properties whose attribute is (READONLY, NON_ENUMERABLE, PERMANENT) since there are many properties (>=68) with those attributes. This way code can be simpler at call sites in those cases

object.insert_internal_property("length", 1);

@HalidOdat what do you think about this?

Actually I do not understand why insert_property must return an Option.

If there already was a property with with the same key then a the old property is returned and the new property is put inplace, other wise one is returned this is what HasHMap::insert() does.

However, I think it'll also be handy to have a function to insert properties whose attribute is (READONLY, NON_ENUMERABLE, PERMANENT) since there are many properties (>=68) with those attributes. This way code can be simpler at call sites in those cases

We have a Attribute::DEFAULT with (READONLY, NON_ENUMERABLE, PERMANENT):

object.insert_property("length", 10, Attribute::DEFAULT);

Having the property be explicit, as the spec does, is nice. If we have multiple places we can factor it out:

let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT;
object.insert_property("length1", 1, attribute);
object.insert_property("length2", 2, attribute);
object.insert_property("length3", 3, attribute);
object.insert_property("length4", 4, attribute);
object.insert_property("length5", 5, attribute);
object.insert_property("length6", 6, attribute);

To me the name insert_internal_property is not descriptive of what it does.

We have a Attribute::DEFAULT with (READONLY, NON_ENUMERABLE, PERMANENT):

I should have taken a closer look before itself. Sorry about that.

We can then have the insert_property with the signature as suggested by you. I can get started with this.

Actually, there's one more method which is used to insert properties: insert_field. In case we want all property inserts to take an explicit attribute as argument, then we must remove it.

Actually, there's one more method which is used to insert properties: insert_field. In case we want all property inserts to take an explicit attribute as argument, then we must remove it.

Yes. the insert_field should be removed.

I was just looking at this again. I think the current insert_property is named appropriately.
For inserting new properties(by specifying Value and Attribute), I think insert_field is better suited than plain insert.
We can have a new insert_field with the signature you had suggested previously.

#[inline]
pub(crate) fn insert_field<K>(&mut self, key: K value: V, attribute: Attribute) -> Option<Property>
where
    K: Into<PropertyKey>,
    V: Into<Value>,
{
    self.insert(key.into(), Property::data_descriptor(value.into(), attribute))
}

Sorry for bringing this naming issue up and dragging this a bit too much :sweat_smile:.

Hmmm. I think it's fine to call it insert the only thing that can be inserted is a property descriptor.
The property descriptor are of two types data descriptor and accessor, so calling it insert_property (by "property" we mean a normal property like "length" not a property descriptor) is fine, in the future we when we will support acessors we will have a insert_accessor.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

croraf picture croraf  路  4Comments

jasonwilliams picture jasonwilliams  路  4Comments

jasonwilliams picture jasonwilliams  路  6Comments

elasmojs picture elasmojs  路  4Comments

elasmojs picture elasmojs  路  5Comments