diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2020-06-07 10:53:14 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-08 09:57:29 +0200 |
commit | 4e33fbdb67304778a67c8d68b0b3500ae36b935b (patch) | |
tree | 1de1f6b29d6575bc8ff2aed5d767f925443a855e /Libraries/LibJS/Runtime | |
parent | f306ddb78b6ff14d0c747383605203a605221014 (diff) | |
download | serenity-4e33fbdb67304778a67c8d68b0b3500ae36b935b.zip |
LibJS: Add interpreter exception checks
Diffstat (limited to 'Libraries/LibJS/Runtime')
-rw-r--r-- | Libraries/LibJS/Runtime/ArrayPrototype.cpp | 22 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/BoundFunction.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ErrorPrototype.cpp | 4 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/GlobalObject.h | 4 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.cpp | 74 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ProxyObject.cpp | 23 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ReflectObject.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/StringConstructor.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.cpp | 4 |
9 files changed, 106 insertions, 31 deletions
diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index f151ac45d3..4d103fa47f 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -170,6 +170,8 @@ Value ArrayPrototype::map(Interpreter& interpreter) new_array->indexed_properties().set_array_like_size(initial_length); for_each_item(interpreter, "map", [&](auto index, auto, auto callback_result) { new_array->put(index, callback_result); + if (interpreter.exception()) + return IterationDecision::Break; return IterationDecision::Continue; }); return Value(new_array); @@ -193,8 +195,11 @@ Value ArrayPrototype::push(Interpreter& interpreter) auto new_length = length + argument_count; if (new_length > MAX_ARRAY_LIKE_INDEX) return interpreter.throw_exception<TypeError>("Maximum array size exceeded"); - for (size_t i = 0; i < argument_count; ++i) + for (size_t i = 0; i < argument_count; ++i) { this_object->put(length + i, interpreter.argument(i)); + if (interpreter.exception()) + return {}; + } auto new_length_value = Value((i32)new_length); this_object->put("length", new_length_value); if (interpreter.exception()) @@ -233,6 +238,8 @@ Value ArrayPrototype::pop(Interpreter& interpreter) if (interpreter.exception()) return {}; this_object->delete_property(index); + if (interpreter.exception()) + return {}; this_object->put("length", Value((i32)index)); if (interpreter.exception()) return {}; @@ -749,15 +756,18 @@ Value ArrayPrototype::splice(Interpreter& interpreter) if (!from.is_empty()) { this_object->put(to, from); - if (interpreter.exception()) - return {}; } else { this_object->delete_property(to); } + if (interpreter.exception()) + return {}; } - for (size_t i = initial_length; i > new_length; --i) + for (size_t i = initial_length; i > new_length; --i) { this_object->delete_property(i - 1); + if (interpreter.exception()) + return {}; + } } else if (insert_count > actual_delete_count) { for (size_t i = initial_length - actual_delete_count; i > actual_start; --i) { auto from = this_object->get(i + actual_delete_count - 1); @@ -768,11 +778,11 @@ Value ArrayPrototype::splice(Interpreter& interpreter) if (!from.is_empty()) { this_object->put(to, from); - if (interpreter.exception()) - return {}; } else { this_object->delete_property(to); } + if (interpreter.exception()) + return {}; } } diff --git a/Libraries/LibJS/Runtime/BoundFunction.cpp b/Libraries/LibJS/Runtime/BoundFunction.cpp index 19fb259430..55e4a5c53c 100644 --- a/Libraries/LibJS/Runtime/BoundFunction.cpp +++ b/Libraries/LibJS/Runtime/BoundFunction.cpp @@ -52,6 +52,8 @@ Value BoundFunction::construct(Interpreter& interpreter) { if (auto this_value = interpreter.this_value(); m_constructor_prototype && this_value.is_object()) { this_value.as_object().set_prototype(m_constructor_prototype); + if (interpreter.exception()) + return {}; } return m_target_function->construct(interpreter); } diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp index cdc34fe58b..8febdc320c 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -91,6 +91,8 @@ Value ErrorPrototype::to_string(Interpreter& interpreter) String name = "Error"; auto name_property = this_object.get("name"); + if (interpreter.exception()) + return {}; if (!name_property.is_empty() && !name_property.is_undefined()) { name = name_property.to_string(interpreter); if (interpreter.exception()) @@ -99,6 +101,8 @@ Value ErrorPrototype::to_string(Interpreter& interpreter) String message = ""; auto message_property = this_object.get("message"); + if (interpreter.exception()) + return {}; if (!message_property.is_empty() && !message_property.is_undefined()) { message = message_property.to_string(interpreter); if (interpreter.exception()) diff --git a/Libraries/LibJS/Runtime/GlobalObject.h b/Libraries/LibJS/Runtime/GlobalObject.h index 8db573598b..9534c9e131 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.h +++ b/Libraries/LibJS/Runtime/GlobalObject.h @@ -74,7 +74,11 @@ inline void GlobalObject::add_constructor(const FlyString& property_name, Constr { constructor = heap().allocate<ConstructorType>(); constructor->define_property("name", js_string(heap(), property_name), Attribute::Configurable); + if (interpreter().exception()) + return; prototype.define_property("constructor", constructor, Attribute::Writable | Attribute::Configurable); + if (interpreter().exception()) + return; define_property(property_name, constructor, Attribute::Writable | Attribute::Configurable); } diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 64f5e647d3..01c57a17d2 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -44,8 +44,6 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(Interpreter& interpreter, { PropertyAttributes attributes; if (object.has_property("configurable")) { - if (interpreter.exception()) - return {}; attributes.set_has_configurable(); if (object.get("configurable").value_or(Value(false)).to_boolean()) attributes.set_configurable(); @@ -53,8 +51,6 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(Interpreter& interpreter, return {}; } if (object.has_property("enumerable")) { - if (interpreter.exception()) - return {}; attributes.set_has_enumerable(); if (object.get("enumerable").value_or(Value(false)).to_boolean()) attributes.set_enumerable(); @@ -62,8 +58,6 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(Interpreter& interpreter, return {}; } if (object.has_property("writable")) { - if (interpreter.exception()) - return {}; attributes.set_has_writable(); if (object.get("writable").value_or(Value(false)).to_boolean()) attributes.set_writable(); @@ -71,10 +65,16 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(Interpreter& interpreter, return {}; } PropertyDescriptor descriptor { attributes, object.get("value"), nullptr, nullptr }; + if (interpreter.exception()) + return {}; auto getter = object.get("get"); + if (interpreter.exception()) + return {}; if (getter.is_function()) descriptor.getter = &getter.as_function(); auto setter = object.get("set"); + if (interpreter.exception()) + return {}; if (setter.is_function()) descriptor.setter = &setter.as_function(); return descriptor; @@ -126,6 +126,8 @@ bool Object::set_prototype(Object* new_prototype) bool Object::has_prototype(const Object* prototype) const { for (auto* object = this->prototype(); object; object = object->prototype()) { + if (interpreter().exception()) + return false; if (object == prototype) return true; } @@ -179,9 +181,15 @@ Value Object::get_own_properties(const Object& this_object, GetOwnPropertyMode k } else { auto* entry_array = Array::create(interpreter().global_object()); entry_array->define_property(0, js_string(interpreter(), String::number(i))); + if (interpreter().exception()) + return {}; entry_array->define_property(1, js_string(interpreter(), String::format("%c", str[i]))); + if (interpreter().exception()) + return {}; properties_array->define_property(i, entry_array); } + if (interpreter().exception()) + return {}; } return properties_array; @@ -197,16 +205,18 @@ Value Object::get_own_properties(const Object& this_object, GetOwnPropertyMode k properties_array->define_property(property_index, js_string(interpreter(), String::number(entry.index()))); } else if (kind == GetOwnPropertyMode::Value) { properties_array->define_property(property_index, value_and_attributes.value); - if (interpreter().exception()) - return {}; } else { auto* entry_array = Array::create(interpreter().global_object()); entry_array->define_property(0, js_string(interpreter(), String::number(entry.index()))); + if (interpreter().exception()) + return {}; entry_array->define_property(1, value_and_attributes.value); if (interpreter().exception()) return {}; properties_array->define_property(property_index, entry_array); } + if (interpreter().exception()) + return {}; ++property_index; } @@ -221,16 +231,18 @@ Value Object::get_own_properties(const Object& this_object, GetOwnPropertyMode k properties_array->define_property(offset, js_string(interpreter(), it.key)); } else if (kind == GetOwnPropertyMode::Value) { properties_array->define_property(offset, this_object.get(it.key)); - if (interpreter().exception()) - return {}; } else { auto* entry_array = Array::create(interpreter().global_object()); entry_array->define_property(0, js_string(interpreter(), it.key)); + if (interpreter().exception()) + return {}; entry_array->define_property(1, this_object.get(it.key)); if (interpreter().exception()) return {}; properties_array->define_property(offset, entry_array); } + if (interpreter().exception()) + return {}; } return properties_array; @@ -284,16 +296,29 @@ Value Object::get_own_property_descriptor_object(PropertyName property_name) con auto* descriptor_object = Object::create_empty(interpreter(), interpreter().global_object()); descriptor_object->define_property("enumerable", Value(descriptor.attributes.is_enumerable())); + if (interpreter().exception()) + return {}; descriptor_object->define_property("configurable", Value(descriptor.attributes.is_configurable())); + if (interpreter().exception()) + return {}; if (descriptor.is_data_descriptor()) { descriptor_object->define_property("value", descriptor.value.value_or(js_undefined())); + if (interpreter().exception()) + return {}; descriptor_object->define_property("writable", Value(descriptor.attributes.is_writable())); + if (interpreter().exception()) + return {}; } else if (descriptor.is_accessor_descriptor()) { if (descriptor.getter) { descriptor_object->define_property("get", Value(descriptor.getter)); + if (interpreter().exception()) + return {}; } - if (descriptor.setter) + if (descriptor.setter) { descriptor_object->define_property("set", Value(descriptor.setter)); + if (interpreter().exception()) + return {}; + } } return descriptor_object; } @@ -309,8 +334,6 @@ bool Object::define_property(const FlyString& property_name, const Object& descr bool is_accessor_property = descriptor.has_property("get") || descriptor.has_property("set"); PropertyAttributes attributes; if (descriptor.has_property("configurable")) { - if (interpreter().exception()) - return false; attributes.set_has_configurable(); if (descriptor.get("configurable").value_or(Value(false)).to_boolean()) attributes.set_configurable(); @@ -318,8 +341,6 @@ bool Object::define_property(const FlyString& property_name, const Object& descr return false; } if (descriptor.has_property("enumerable")) { - if (interpreter().exception()) - return false; attributes.set_has_enumerable(); if (descriptor.get("enumerable").value_or(Value(false)).to_boolean()) attributes.set_enumerable(); @@ -369,8 +390,6 @@ bool Object::define_property(const FlyString& property_name, const Object& descr if (interpreter().exception()) return {}; if (descriptor.has_property("writable")) { - if (interpreter().exception()) - return false; attributes.set_has_writable(); if (descriptor.get("writable").value_or(Value(false)).to_boolean()) attributes.set_writable(); @@ -523,6 +542,11 @@ Value Object::delete_property(PropertyName property_name) ASSERT(property_name.is_valid()); if (property_name.is_number()) return Value(m_indexed_properties.remove(property_name.as_number())); + bool ok; + int property_index = property_name.as_string().to_int(ok); + if (ok && property_index >= 0) + return Value(m_indexed_properties.remove(property_name.as_number())); + auto metadata = shape().lookup(property_name.as_string()); if (!metadata.has_value()) return Value(true); @@ -565,6 +589,8 @@ Value Object::get_by_index(u32 property_index) const return {}; } object = object->prototype(); + if (interpreter().exception()) + return {}; } return {}; } @@ -583,9 +609,13 @@ Value Object::get(PropertyName property_name) const const Object* object = this; while (object) { auto value = object->get_own_property(*this, property_name); + if (interpreter().exception()) + return {}; if (!value.is_empty()) return value; object = object->prototype(); + if (interpreter().exception()) + return {}; } return {}; } @@ -611,6 +641,8 @@ bool Object::put_by_index(u32 property_index, Value value) } } object = object->prototype(); + if (interpreter().exception()) + return {}; } return put_own_property_by_index(*this, property_index, value, default_attributes, PutOwnPropertyMode::Put); } @@ -645,6 +677,8 @@ bool Object::put(PropertyName property_name, Value value) } } object = object->prototype(); + if (interpreter().exception()) + return {}; } return put_own_property(*this, property_string, value, default_attributes, PutOwnPropertyMode::Put); } @@ -653,7 +687,11 @@ bool Object::define_native_function(const FlyString& property_name, AK::Function { auto* function = NativeFunction::create(interpreter(), interpreter().global_object(), property_name, move(native_function)); function->define_property("length", Value(length), Attribute::Configurable); + if (interpreter().exception()) + return {}; function->define_property("name", js_string(heap(), property_name), Attribute::Configurable); + if (interpreter().exception()) + return {}; return define_property(property_name, function, attribute); } @@ -681,6 +719,8 @@ bool Object::has_property(PropertyName property_name) const if (object->has_own_property(property_name)) return true; object = object->prototype(); + if (interpreter().exception()) + return false; } return false; } diff --git a/Libraries/LibJS/Runtime/ProxyObject.cpp b/Libraries/LibJS/Runtime/ProxyObject.cpp index aa51276b33..9d83de5475 100644 --- a/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -98,6 +98,8 @@ Object* ProxyObject::prototype() return nullptr; } if (m_target.is_extensible()) { + if (interpreter().exception()) + return nullptr; if (trap_result.is_null()) return nullptr; return &trap_result.as_object(); @@ -175,7 +177,8 @@ bool ProxyObject::is_extensible() const if (interpreter().exception()) return false; if (trap_result != m_target.is_extensible()) { - interpreter().throw_exception<TypeError>("Proxy handler's isExtensible trap violates invariant: return value must match the target's extensibility"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's isExtensible trap violates invariant: return value must match the target's extensibility"); return false; } return trap_result; @@ -202,7 +205,8 @@ bool ProxyObject::prevent_extensions() if (interpreter().exception()) return false; if (trap_result && m_target.is_extensible()) { - interpreter().throw_exception<TypeError>("Proxy handler's preventExtensions trap violates invariant: cannot return true if the target object is extensible"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's preventExtensions trap violates invariant: cannot return true if the target object is extensible"); return false; } return trap_result; @@ -244,7 +248,8 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa return {}; } if (!m_target.is_extensible()) { - interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report a property as being undefined if it exists as an own property of the target and the target is non-extensible"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report a property as being undefined if it exists as an own property of the target and the target is non-extensible"); return {}; } return {}; @@ -253,7 +258,8 @@ Optional<PropertyDescriptor> ProxyObject::get_own_property_descriptor(PropertyNa if (interpreter().exception()) return {}; if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), result_desc, target_desc)) { - interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target"); return {}; } if (!result_desc.attributes.is_configurable() && (!target_desc.has_value() || target_desc.value().attributes.is_configurable())) { @@ -295,7 +301,8 @@ bool ProxyObject::define_property(const FlyString& property_name, const Object& return false; if (!target_desc.has_value()) { if (!m_target.is_extensible()) { - interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: a property cannot be reported as being defined if the property does not exist on the target and the target is non-extensible"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: a property cannot be reported as being defined if the property does not exist on the target and the target is non-extensible"); return false; } if (setting_config_false) { @@ -304,7 +311,8 @@ bool ProxyObject::define_property(const FlyString& property_name, const Object& } } else { if (!is_compatible_property_descriptor(interpreter(), m_target.is_extensible(), PropertyDescriptor::from_dictionary(interpreter(), descriptor), target_desc)) { - interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: the new descriptor is not compatible with the existing descriptor of the property on the target"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's defineProperty trap violates invariant: the new descriptor is not compatible with the existing descriptor of the property on the target"); return false; } if (setting_config_false && target_desc.value().attributes.is_configurable()) { @@ -346,7 +354,8 @@ bool ProxyObject::has_property(PropertyName name) const return false; } if (!m_target.is_extensible()) { - interpreter().throw_exception<TypeError>("Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exist on the target and the target is non-extensible"); + if (!interpreter().exception()) + interpreter().throw_exception<TypeError>("Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exist on the target and the target is non-extensible"); return false; } } diff --git a/Libraries/LibJS/Runtime/ReflectObject.cpp b/Libraries/LibJS/Runtime/ReflectObject.cpp index c81ba0fea2..917c00c436 100644 --- a/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -145,6 +145,8 @@ Value ReflectObject::define_property(Interpreter& interpreter) return {}; auto& descriptor = interpreter.argument(2).as_object(); auto success = target->define_property(property_key, descriptor, false); + if (interpreter.exception()) + return {}; return Value(success); } diff --git a/Libraries/LibJS/Runtime/StringConstructor.cpp b/Libraries/LibJS/Runtime/StringConstructor.cpp index 314683eced..d5a633306e 100644 --- a/Libraries/LibJS/Runtime/StringConstructor.cpp +++ b/Libraries/LibJS/Runtime/StringConstructor.cpp @@ -79,6 +79,8 @@ Value StringConstructor::raw(Interpreter& interpreter) return {}; auto raw = template_object->get("raw"); + if (interpreter.exception()) + return {}; if (raw.is_empty() || raw.is_undefined() || raw.is_null()) { interpreter.throw_exception<TypeError>(String::format("Cannot convert property 'raw' to object from %s", raw.is_null() ? "null" : "undefined")); return {}; diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index dacc2d31a3..13ff1ab920 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -675,11 +675,13 @@ Value in(Interpreter& interpreter, Value lhs, Value rhs) return Value(rhs.as_object().has_property(lhs_string)); } -Value instance_of(Interpreter&, Value lhs, Value rhs) +Value instance_of(Interpreter& interpreter, Value lhs, Value rhs) { if (!lhs.is_object() || !rhs.is_object()) return Value(false); auto constructor_prototype_property = rhs.as_object().get("prototype"); + if (interpreter.exception()) + return {}; if (!constructor_prototype_property.is_object()) return Value(false); return Value(lhs.as_object().has_prototype(&constructor_prototype_property.as_object())); |