LibJS: Make class prototype property non-writable
ClassDefinitionEvaluation calls MakeConstructor with false for the writablePrototype argument, so class constructors get a non-writable, non-enumerable, non-configurable prototype property. We were using the ordinary function attributes instead, which also allowed static class elements named "prototype" to redefine the property. Add LibJS coverage for the constructor and prototype descriptors, and for static methods/accessors that attempt to define "prototype".
This commit is contained in:
parent
a6e642790f
commit
991ba90d40
3 changed files with 37 additions and 1 deletions
|
|
@ -97,7 +97,7 @@ ThrowCompletionOr<ECMAScriptFunctionObject*> construct_class(
|
|||
class_constructor->set_name(class_name);
|
||||
class_constructor->set_home_object(prototype);
|
||||
class_constructor->set_is_class_constructor();
|
||||
class_constructor->define_direct_property(vm.names.prototype, prototype, Attribute::Writable);
|
||||
class_constructor->define_direct_property(vm.names.prototype, prototype, 0);
|
||||
TRY(class_constructor->internal_set_prototype_of(constructor_parent));
|
||||
|
||||
if (blueprint.has_super_class)
|
||||
|
|
|
|||
|
|
@ -3,3 +3,19 @@ test("class properties", () => {
|
|||
expect(A.name).toBe("A");
|
||||
expect(A).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("class constructor prototype property descriptor", () => {
|
||||
class A {}
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(A, "prototype");
|
||||
expect(descriptor.value).toBe(A.prototype);
|
||||
expect(descriptor.writable).toBeFalse();
|
||||
expect(descriptor.enumerable).toBeFalse();
|
||||
expect(descriptor.configurable).toBeFalse();
|
||||
|
||||
const constructorDescriptor = Object.getOwnPropertyDescriptor(A.prototype, "constructor");
|
||||
expect(constructorDescriptor.value).toBe(A);
|
||||
expect(constructorDescriptor.writable).toBeTrue();
|
||||
expect(constructorDescriptor.enumerable).toBeFalse();
|
||||
expect(constructorDescriptor.configurable).toBeTrue();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -71,6 +71,26 @@ test("static method overriding", () => {
|
|||
expect(Child.method()).toBe(10);
|
||||
});
|
||||
|
||||
test("static elements cannot redefine prototype property", () => {
|
||||
expect(() => {
|
||||
class A {
|
||||
static ["prototype"]() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
static get ["prototype"]() {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
|
||||
expect(() => {
|
||||
class A {
|
||||
static set ["prototype"](value) {}
|
||||
}
|
||||
}).toThrow(TypeError);
|
||||
});
|
||||
|
||||
test("static function named 'async'", () => {
|
||||
class A {
|
||||
static async() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue