1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 09:17:36 +00:00

LibJS: Disallow changing the prototype of non-extensible objects

Object::set_prototype() now returns a boolean indicating success.
Setting the prototype to an identical object is always considered
successful, even if the object is non-extensible.
This commit is contained in:
Linus Groh 2020-06-02 12:32:54 +01:00 committed by Andreas Kling
parent 8cf1ded478
commit b958e4f573
4 changed files with 22 additions and 6 deletions

View file

@ -69,15 +69,18 @@ const Object* Object::prototype() const
return shape().prototype(); return shape().prototype();
} }
void Object::set_prototype(Object* new_prototype) bool Object::set_prototype(Object* new_prototype)
{ {
if (prototype() == new_prototype) if (prototype() == new_prototype)
return; return true;
if (!m_is_extensible)
return false;
if (shape().is_unique()) { if (shape().is_unique()) {
shape().set_prototype_without_transition(new_prototype); shape().set_prototype_without_transition(new_prototype);
return; return true;
} }
m_shape = m_shape->create_prototype_transition(new_prototype); m_shape = m_shape->create_prototype_transition(new_prototype);
return true;
} }
bool Object::has_prototype(const Object* prototype) const bool Object::has_prototype(const Object* prototype) const

View file

@ -95,7 +95,7 @@ public:
Object* prototype(); Object* prototype();
const Object* prototype() const; const Object* prototype() const;
void set_prototype(Object*); bool set_prototype(Object* prototype);
bool has_prototype(const Object* prototype) const; bool has_prototype(const Object* prototype) const;
bool is_extensible() const { return m_is_extensible; } bool is_extensible() const { return m_is_extensible; }

View file

@ -112,7 +112,10 @@ Value ObjectConstructor::set_prototype_of(Interpreter& interpreter)
interpreter.throw_exception<TypeError>("Prototype must be null or object"); interpreter.throw_exception<TypeError>("Prototype must be null or object");
return {}; return {};
} }
object->set_prototype(prototype); if (!object->set_prototype(prototype)) {
interpreter.throw_exception<TypeError>("Can't set prototype of non-extensible object");
return {};
}
return object; return object;
} }

View file

@ -11,7 +11,17 @@ try {
}); });
o = {}; o = {};
assert(Object.setPrototypeOf(o, {}) === o); p = {};
assert(Object.setPrototypeOf(o, p) === o);
Object.preventExtensions(o);
assertThrowsError(() => {
Object.setPrototypeOf(o, {});
}, {
error: TypeError,
message: "Can't set prototype of non-extensible object"
});
assert(Object.setPrototypeOf(o, p) === o);
console.log("PASS"); console.log("PASS");
} catch (e) { } catch (e) {