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:
parent
8cf1ded478
commit
b958e4f573
4 changed files with 22 additions and 6 deletions
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue