summaryrefslogtreecommitdiff
path: root/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2020-06-07 10:53:14 -0700
committerAndreas Kling <kling@serenityos.org>2020-06-08 09:57:29 +0200
commit4e33fbdb67304778a67c8d68b0b3500ae36b935b (patch)
tree1de1f6b29d6575bc8ff2aed5d767f925443a855e /Libraries/LibJS/Runtime
parentf306ddb78b6ff14d0c747383605203a605221014 (diff)
downloadserenity-4e33fbdb67304778a67c8d68b0b3500ae36b935b.zip
LibJS: Add interpreter exception checks
Diffstat (limited to 'Libraries/LibJS/Runtime')
-rw-r--r--Libraries/LibJS/Runtime/ArrayPrototype.cpp22
-rw-r--r--Libraries/LibJS/Runtime/BoundFunction.cpp2
-rw-r--r--Libraries/LibJS/Runtime/ErrorPrototype.cpp4
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.h4
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp74
-rw-r--r--Libraries/LibJS/Runtime/ProxyObject.cpp23
-rw-r--r--Libraries/LibJS/Runtime/ReflectObject.cpp2
-rw-r--r--Libraries/LibJS/Runtime/StringConstructor.cpp2
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp4
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()));