mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 02:12:09 -05:00
LibJS: Check if class extends value has a valid prototype
If we have a function as class extends value, we still cannot assume that it has a prototype property and that property has a function or null as its value - blindly calling to_object() on it may fail. Fixes #5075.
This commit is contained in:
parent
397f432aed
commit
ea55453c2a
3 changed files with 27 additions and 3 deletions
|
@ -810,7 +810,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
|||
if (interpreter.exception())
|
||||
return {};
|
||||
if (!super_constructor.is_function() && !super_constructor.is_null()) {
|
||||
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects());
|
||||
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ClassExtendsValueNotAConstructorOrNull, super_constructor.to_string_without_side_effects());
|
||||
return {};
|
||||
}
|
||||
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
|
||||
|
@ -818,9 +818,18 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
|||
|
||||
Object* super_constructor_prototype = nullptr;
|
||||
if (!super_constructor.is_null()) {
|
||||
super_constructor_prototype = &super_constructor.as_object().get(vm.names.prototype).as_object();
|
||||
auto super_constructor_prototype_value = super_constructor.as_object().get(vm.names.prototype);
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
if (!super_constructor_prototype_value.is_object() && !super_constructor_prototype_value.is_null()) {
|
||||
interpreter.vm().throw_exception<TypeError>(global_object, ErrorType::ClassExtendsValueInvalidPrototype, super_constructor_prototype_value.to_string_without_side_effects());
|
||||
return {};
|
||||
}
|
||||
if (super_constructor_prototype_value.is_object()) {
|
||||
super_constructor_prototype = &super_constructor_prototype_value.as_object();
|
||||
if (interpreter.exception())
|
||||
return {};
|
||||
}
|
||||
}
|
||||
prototype->set_prototype(super_constructor_prototype);
|
||||
|
||||
|
|
|
@ -36,8 +36,9 @@
|
|||
M(BigIntIntArgument, "BigInt argument must be an integer") \
|
||||
M(BigIntInvalidValue, "Invalid value for BigInt: {}") \
|
||||
M(ClassConstructorWithoutNew, "Class constructor {} must be called with 'new'") \
|
||||
M(ClassExtendsValueNotAConstructorOrNull, "Class extends value {} is not a constructor or null") \
|
||||
M(ClassExtendsValueInvalidPrototype, "Class extends value has an invalid prototype {}") \
|
||||
M(ClassIsAbstract, "Abstract class {} cannot be constructed directly") \
|
||||
M(ClassDoesNotExtendAConstructorOrNull, "Class extends value {} is not a constructor or null") \
|
||||
M(ConstructorWithoutNew, "{} constructor must be called with 'new'") \
|
||||
M(Convert, "Cannot convert {} to {}") \
|
||||
M(ConvertUndefinedToObject, "Cannot convert undefined to object") \
|
||||
|
|
|
@ -33,3 +33,17 @@ test("extending String", () => {
|
|||
const ms2 = new MyString2("abc");
|
||||
expect(ms2.charAt(1)).toBe("#b");
|
||||
});
|
||||
|
||||
test("class extends value is invalid", () => {
|
||||
expect(() => {
|
||||
class A extends 123 {}
|
||||
}).toThrowWithMessage(TypeError, "Class extends value 123 is not a constructor or null");
|
||||
});
|
||||
|
||||
test("class extends value has invalid prototype", () => {
|
||||
function f() {}
|
||||
f.prototype = 123;
|
||||
expect(() => {
|
||||
class A extends f {}
|
||||
}).toThrowWithMessage(TypeError, "Class extends value has an invalid prototype 123");
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue