From 476094922b6dbbc252a076aecca9cc0d172e540e Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Mon, 18 May 2020 00:28:00 +0100 Subject: [PATCH] LibJS: Pass Interpreter& to Value::to_number() et al. This patch is unfortunately rather large and might make some things feel bloated, but it is necessary to fix a few flaws in LibJS, primarily blindly coercing values to numbers without exception checks - i.e. interpreter.argument(0).to_i32(); // can fail!!! Some examples where the interpreter would actually crash: var o = { toString: () => { throw Error() } }; +o; o - 1; "foo".charAt(o); "bar".repeat(o); To fix this, we now have the following... to_double(Interpreter&) to_i32() to_i32(Interpreter&) to_size_t() to_size_t(Interpreter&) ...and a whole lot of exception checking. There's intentionally no to_double(), use as_double() directly instead. This way we still can use these convenient utility functions but don't need to check for exceptions if we are sure the value already is a number. Fixes #2267. --- Libraries/LibJS/AST.cpp | 5 +- Libraries/LibJS/Runtime/Array.cpp | 4 +- Libraries/LibJS/Runtime/ArrayPrototype.cpp | 27 +- Libraries/LibJS/Runtime/ErrorPrototype.cpp | 12 +- Libraries/LibJS/Runtime/FunctionPrototype.cpp | 6 +- Libraries/LibJS/Runtime/GlobalObject.cpp | 13 +- Libraries/LibJS/Runtime/MathObject.cpp | 59 +++-- Libraries/LibJS/Runtime/NumberConstructor.cpp | 15 +- Libraries/LibJS/Runtime/ReflectObject.cpp | 11 +- Libraries/LibJS/Runtime/StringPrototype.cpp | 52 ++-- Libraries/LibJS/Runtime/Uint8ClampedArray.cpp | 5 +- Libraries/LibJS/Runtime/Value.cpp | 250 +++++++++++++----- Libraries/LibJS/Runtime/Value.h | 8 +- Libraries/LibJS/Tests/to-number-exception.js | 38 +++ .../CanvasRenderingContext2DWrapper.cpp | 149 ++++++++--- Libraries/LibWeb/Bindings/WindowObject.cpp | 17 +- Userland/js.cpp | 7 +- 17 files changed, 491 insertions(+), 187 deletions(-) create mode 100644 Libraries/LibJS/Tests/to-number-exception.js diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 9e7ef87923..1811e8ab84 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -941,11 +941,12 @@ Value UpdateExpression::execute(Interpreter& interpreter) const auto reference = m_argument->to_reference(interpreter); if (interpreter.exception()) return {}; - auto old_value = reference.get(interpreter); if (interpreter.exception()) return {}; - old_value = old_value.to_number(); + old_value = old_value.to_number(interpreter); + if (interpreter.exception()) + return {}; int op_result = 0; switch (m_op) { diff --git a/Libraries/LibJS/Runtime/Array.cpp b/Libraries/LibJS/Runtime/Array.cpp index 2b1d0eae59..b9c6749043 100644 --- a/Libraries/LibJS/Runtime/Array.cpp +++ b/Libraries/LibJS/Runtime/Array.cpp @@ -74,7 +74,9 @@ void Array::length_setter(Interpreter& interpreter, Value value) auto* array = array_from(interpreter); if (!array) return; - auto length = value.to_number(); + auto length = value.to_number(interpreter); + if (interpreter.exception()) + return; if (length.is_nan() || length.is_infinity() || length.as_double() < 0) { interpreter.throw_exception("Invalid array length"); return; diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp index a137c20fd3..333c11046e 100644 --- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -297,7 +297,9 @@ Value ArrayPrototype::slice(Interpreter& interpreter) } ssize_t array_size = static_cast(array->elements().size()); - auto start_slice = interpreter.argument(0).to_i32(); + auto start_slice = interpreter.argument(0).to_i32(interpreter); + if (interpreter.exception()) + return {}; auto end_slice = array_size; if (start_slice > array_size) @@ -307,8 +309,9 @@ Value ArrayPrototype::slice(Interpreter& interpreter) start_slice = end_slice + start_slice; if (interpreter.argument_count() >= 2) { - end_slice = interpreter.argument(1).to_i32(); - + end_slice = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; if (end_slice < 0) end_slice = array_size + end_slice; else if (end_slice > array_size) @@ -336,11 +339,11 @@ Value ArrayPrototype::index_of(Interpreter& interpreter) i32 from_index = 0; if (interpreter.argument_count() >= 2) { - from_index = interpreter.argument(1).to_number().to_i32(); - + from_index = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; if (from_index >= array_size) return Value(-1); - auto negative_min_index = ((array_size - 1) * -1); if (from_index < negative_min_index) from_index = 0; @@ -390,11 +393,11 @@ Value ArrayPrototype::last_index_of(Interpreter& interpreter) i32 from_index = 0; if (interpreter.argument_count() >= 2) { - from_index = interpreter.argument(1).to_number().to_i32(); - + from_index = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; if (from_index >= array_size) return Value(-1); - auto negative_min_index = ((array_size - 1) * -1); if (from_index < negative_min_index) from_index = 0; @@ -424,11 +427,11 @@ Value ArrayPrototype::includes(Interpreter& interpreter) i32 from_index = 0; if (interpreter.argument_count() >= 2) { - from_index = interpreter.argument(1).to_i32(); - + from_index = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; if (from_index >= array_size) return Value(false); - auto negative_min_index = ((array_size - 1) * -1); if (from_index < negative_min_index) from_index = 0; diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp index b1f2afe684..83bb5bb6f3 100644 --- a/Libraries/LibJS/Runtime/ErrorPrototype.cpp +++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp @@ -90,17 +90,17 @@ Value ErrorPrototype::to_string(Interpreter& interpreter) auto& this_object = interpreter.this_value().as_object(); String name = "Error"; - auto object_name_property = this_object.get("name"); - if (!object_name_property.is_empty() && !object_name_property.is_undefined()) { - name = object_name_property.to_string(interpreter); + auto name_property = this_object.get("name"); + if (!name_property.is_empty() && !name_property.is_undefined()) { + name = name_property.to_string(interpreter); if (interpreter.exception()) return {}; } String message = ""; - auto object_message_property = this_object.get("message"); - if (!object_message_property.is_empty() && !object_message_property.is_undefined()) { - message = object_message_property.to_string(interpreter); + auto message_property = this_object.get("message"); + if (!message_property.is_empty() && !message_property.is_undefined()) { + message = message_property.to_string(interpreter); if (interpreter.exception()) return {}; } diff --git a/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Libraries/LibJS/Runtime/FunctionPrototype.cpp index e499e4003c..c3c6af72ae 100644 --- a/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -73,7 +73,11 @@ Value FunctionPrototype::apply(Interpreter& interpreter) if (!arg_array.is_object()) return interpreter.throw_exception("argument array must be an object"); auto length_property = arg_array.as_object().get("length"); - auto length = length_property.to_size_t(); + if (interpreter.exception()) + return {}; + auto length = length_property.to_size_t(interpreter); + if (interpreter.exception()) + return {}; MarkedValueList arguments(interpreter.heap()); for (size_t i = 0; i < length; ++i) { auto element = arg_array.as_object().get(String::number(i)); diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp index e45e65d7c9..3ebbb2665f 100644 --- a/Libraries/LibJS/Runtime/GlobalObject.cpp +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -137,12 +137,18 @@ Value GlobalObject::gc(Interpreter& interpreter) Value GlobalObject::is_nan(Interpreter& interpreter) { - return Value(interpreter.argument(0).to_number().is_nan()); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(number.is_nan()); } Value GlobalObject::is_finite(Interpreter& interpreter) { - return Value(interpreter.argument(0).to_number().is_finite_number()); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(number.is_finite_number()); } Value GlobalObject::parse_float(Interpreter& interpreter) @@ -151,7 +157,8 @@ Value GlobalObject::parse_float(Interpreter& interpreter) if (interpreter.exception()) return {}; for (size_t length = string.length(); length > 0; --length) { - auto number = Value(js_string(interpreter, string.substring(0, length))).to_number(); + // This can't throw, so no exception check is fine. + auto number = Value(js_string(interpreter, string.substring(0, length))).to_number(interpreter); if (!number.is_nan()) return number; } diff --git a/Libraries/LibJS/Runtime/MathObject.cpp b/Libraries/LibJS/Runtime/MathObject.cpp index b538591a44..133d439759 100644 --- a/Libraries/LibJS/Runtime/MathObject.cpp +++ b/Libraries/LibJS/Runtime/MathObject.cpp @@ -67,7 +67,9 @@ MathObject::~MathObject() Value MathObject::abs(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(number.as_double() >= 0 ? number.as_double() : -number.as_double()); @@ -85,7 +87,9 @@ Value MathObject::random(Interpreter&) Value MathObject::sqrt(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::sqrt(number.as_double())); @@ -93,7 +97,9 @@ Value MathObject::sqrt(Interpreter& interpreter) Value MathObject::floor(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::floor(number.as_double())); @@ -101,7 +107,9 @@ Value MathObject::floor(Interpreter& interpreter) Value MathObject::ceil(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::ceil(number.as_double())); @@ -109,7 +117,9 @@ Value MathObject::ceil(Interpreter& interpreter) Value MathObject::round(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::round(number.as_double())); @@ -120,12 +130,13 @@ Value MathObject::max(Interpreter& interpreter) if (!interpreter.argument_count()) return js_negative_infinity(); - if (interpreter.argument_count() == 1) - return interpreter.argument(0).to_number(); - - Value max = interpreter.argument(0).to_number(); + auto max = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; for (size_t i = 1; i < interpreter.argument_count(); ++i) { - Value cur = interpreter.argument(i).to_number(); + auto cur = interpreter.argument(i).to_number(interpreter); + if (interpreter.exception()) + return {}; max = Value(cur.as_double() > max.as_double() ? cur : max); } return max; @@ -136,12 +147,13 @@ Value MathObject::min(Interpreter& interpreter) if (!interpreter.argument_count()) return js_infinity(); - if (interpreter.argument_count() == 1) - return interpreter.argument(0).to_number(); - - Value min = interpreter.argument(0).to_number(); + auto min = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; for (size_t i = 1; i < interpreter.argument_count(); ++i) { - Value cur = interpreter.argument(i).to_number(); + auto cur = interpreter.argument(i).to_number(interpreter); + if (interpreter.exception()) + return {}; min = Value(cur.as_double() < min.as_double() ? cur : min); } return min; @@ -149,10 +161,11 @@ Value MathObject::min(Interpreter& interpreter) Value MathObject::trunc(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); - if (number.as_double() < 0) return MathObject::ceil(interpreter); return MathObject::floor(interpreter); @@ -160,7 +173,9 @@ Value MathObject::trunc(Interpreter& interpreter) Value MathObject::sin(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::sin(number.as_double())); @@ -168,7 +183,9 @@ Value MathObject::sin(Interpreter& interpreter) Value MathObject::cos(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::cos(number.as_double())); @@ -176,7 +193,9 @@ Value MathObject::cos(Interpreter& interpreter) Value MathObject::tan(Interpreter& interpreter) { - auto number = interpreter.argument(0).to_number(); + auto number = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (number.is_nan()) return js_nan(); return Value(::tan(number.as_double())); diff --git a/Libraries/LibJS/Runtime/NumberConstructor.cpp b/Libraries/LibJS/Runtime/NumberConstructor.cpp index ff99b1dc47..221de5af16 100644 --- a/Libraries/LibJS/Runtime/NumberConstructor.cpp +++ b/Libraries/LibJS/Runtime/NumberConstructor.cpp @@ -64,16 +64,17 @@ Value NumberConstructor::call(Interpreter& interpreter) { if (!interpreter.argument_count()) return Value(0); - return interpreter.argument(0).to_number(); + return interpreter.argument(0).to_number(interpreter); } Value NumberConstructor::construct(Interpreter& interpreter) { - double number; - if (!interpreter.argument_count()) - number = 0; - else - number = interpreter.argument(0).to_number().as_double(); + double number = 0; + if (interpreter.argument_count()) { + number = interpreter.argument(0).to_double(interpreter); + if (interpreter.exception()) + return {}; + } return NumberObject::create(interpreter.global_object(), number); } @@ -96,7 +97,7 @@ Value NumberConstructor::is_safe_integer(Interpreter& interpreter) { if (!interpreter.argument(0).is_number()) return Value(false); - auto value = interpreter.argument(0).to_number().as_double(); + auto value = interpreter.argument(0).as_double(); return Value((int64_t)value == value && value >= MIN_SAFE_INTEGER && value <= MAX_SAFE_INTEGER); } diff --git a/Libraries/LibJS/Runtime/ReflectObject.cpp b/Libraries/LibJS/Runtime/ReflectObject.cpp index fca5981cdb..004e497182 100644 --- a/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -64,7 +64,9 @@ static void prepare_arguments_list(Interpreter& interpreter, Value value, Marked auto length_property = arguments_list.get("length"); if (interpreter.exception()) return; - auto length = length_property.to_size_t(); + auto length = length_property.to_size_t(interpreter); + if (interpreter.exception()) + return; for (size_t i = 0; i < length; ++i) { auto element = arguments_list.get(String::number(i)); if (interpreter.exception()) @@ -156,8 +158,11 @@ Value ReflectObject::delete_property(Interpreter& interpreter) auto property_name = PropertyName(property_key.to_string(interpreter)); if (interpreter.exception()) return {}; - if (property_key.to_number().is_finite_number()) { - auto property_key_as_double = property_key.to_double(); + auto property_key_number = property_key.to_number(interpreter); + if (interpreter.exception()) + return {}; + if (property_key_number.is_finite_number()) { + auto property_key_as_double = property_key_number.as_double(); if (property_key_as_double >= 0 && (i32)property_key_as_double == property_key_as_double) property_name = PropertyName(property_key_as_double); } diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp index 10e8b96830..5b3847d1e3 100644 --- a/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -94,8 +94,11 @@ Value StringPrototype::char_at(Interpreter& interpreter) if (string.is_null()) return {}; i32 index = 0; - if (interpreter.argument_count()) - index = interpreter.argument(0).to_i32(); + if (interpreter.argument_count()) { + index = interpreter.argument(0).to_i32(interpreter); + if (interpreter.exception()) + return {}; + } if (index < 0 || index >= static_cast(string.length())) return js_string(interpreter, String::empty()); return js_string(interpreter, string.substring(index, 1)); @@ -108,7 +111,9 @@ Value StringPrototype::repeat(Interpreter& interpreter) return {}; if (!interpreter.argument_count()) return js_string(interpreter, String::empty()); - auto count_value = interpreter.argument(0).to_number(); + auto count_value = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; if (count_value.as_double() < 0) return interpreter.throw_exception("repeat count must be a positive number"); if (count_value.is_infinity()) @@ -134,9 +139,11 @@ Value StringPrototype::starts_with(Interpreter& interpreter) auto search_string_length = search_string.length(); size_t start = 0; if (interpreter.argument_count() > 1) { - auto number = interpreter.argument(1).to_number(); + auto number = interpreter.argument(1).to_number(interpreter); + if (interpreter.exception()) + return {}; if (!number.is_nan()) - start = min(number.to_size_t(), string_length); + start = min(number.to_size_t(interpreter), string_length); } if (start + search_string_length > string_length) return Value(false); @@ -195,7 +202,9 @@ enum class PadPlacement { static Value pad_string(Interpreter& interpreter, const String& string, PadPlacement placement) { - auto max_length = interpreter.argument(0).to_size_t(); + auto max_length = interpreter.argument(0).to_size_t(interpreter); + if (interpreter.exception()) + return {}; if (max_length <= string.length()) return js_string(interpreter, string); @@ -285,11 +294,15 @@ Value StringPrototype::substring(Interpreter& interpreter) return js_string(interpreter, string); auto string_length = string.length(); - auto index_start = min(interpreter.argument(0).to_size_t(), string_length); + auto index_start = min(interpreter.argument(0).to_size_t(interpreter), string_length); + if (interpreter.exception()) + return {}; auto index_end = string_length; - - if (interpreter.argument_count() >= 2) - index_end = min(interpreter.argument(1).to_size_t(), string_length); + if (interpreter.argument_count() >= 2) { + index_end = min(interpreter.argument(1).to_size_t(interpreter), string_length); + if (interpreter.exception()) + return {}; + } if (index_start == index_end) return js_string(interpreter, String("")); @@ -318,7 +331,9 @@ Value StringPrototype::includes(Interpreter& interpreter) size_t position = 0; if (interpreter.argument_count() >= 2) { - position = interpreter.argument(1).to_size_t(); + position = interpreter.argument(1).to_size_t(interpreter); + if (interpreter.exception()) + return {}; if (position >= string.length()) return Value(false); } @@ -341,7 +356,9 @@ Value StringPrototype::slice(Interpreter& interpreter) return js_string(interpreter, string); auto string_length = static_cast(string.length()); - auto index_start = interpreter.argument(0).to_i32(); + auto index_start = interpreter.argument(0).to_i32(interpreter); + if (interpreter.exception()) + return {}; auto index_end = string_length; auto negative_min_index = -(string_length - 1); @@ -351,7 +368,9 @@ Value StringPrototype::slice(Interpreter& interpreter) index_start = string_length + index_start; if (interpreter.argument_count() >= 2) { - index_end = interpreter.argument(1).to_i32(); + index_end = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; if (index_end < negative_min_index) return js_string(interpreter, String::empty()); @@ -387,8 +406,11 @@ Value StringPrototype::last_index_of(Interpreter& interpreter) auto max_index = string.length() - search_string.length(); auto from_index = max_index; - if (interpreter.argument_count() >= 2) - from_index = min(interpreter.argument(1).to_size_t(), max_index); + if (interpreter.argument_count() >= 2) { + from_index = min(interpreter.argument(1).to_size_t(interpreter), max_index); + if (interpreter.exception()) + return {}; + } for (i32 i = from_index; i >= 0; --i) { auto part_view = string.substring_view(i, search_string.length()); diff --git a/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp b/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp index 74cc674a49..4bf1dfcdad 100644 --- a/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp +++ b/Libraries/LibJS/Runtime/Uint8ClampedArray.cpp @@ -70,7 +70,10 @@ bool Uint8ClampedArray::put_by_index(i32 property_index, Value value, u8) // FIXME: Use attributes ASSERT(property_index >= 0); ASSERT(property_index < m_length); - m_data[property_index] = clamp(value.to_i32(), 0, 255); + auto number = value.to_i32(interpreter()); + if (interpreter().exception()) + return {}; + m_data[property_index] = clamp(number, 0, 255); return true; } diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 46c19bc49b..7e7c9c054b 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -36,8 +36,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -96,7 +96,7 @@ String Value::to_string_without_side_effects() const return String::format("[object %s]", as_object().class_name()); } -PrimitiveString* Value::to_primitive_string(Interpreter & interpreter) +PrimitiveString* Value::to_primitive_string(Interpreter& interpreter) { if (is_string()) return &as_string(); @@ -202,7 +202,7 @@ Object* Value::to_object(Interpreter& interpreter) const ASSERT_NOT_REACHED(); } -Value Value::to_number() const +Value Value::to_number(Interpreter& interpreter) const { switch (m_type) { case Type::Empty: @@ -234,58 +234,110 @@ Value Value::to_number() const // FIXME: Get access to the interpreter and throw a TypeError ASSERT_NOT_REACHED(); case Type::Object: - return m_value.as_object->to_primitive(Object::PreferredType::Number).to_number(); + auto primitive = m_value.as_object->to_primitive(Object::PreferredType::Number); + if (interpreter.exception()) + return {}; + return primitive.to_number(interpreter); } ASSERT_NOT_REACHED(); } -i32 Value::to_i32() const +double Value::to_double(Interpreter& interpreter) const { - return static_cast(to_number().as_double()); + auto number = to_number(interpreter); + if (interpreter.exception()) + return 0; + return number.as_double(); } -double Value::to_double() const +i32 Value::to_i32() const { - return to_number().as_double(); + return static_cast(as_double()); +} + +i32 Value::to_i32(Interpreter& interpreter) const +{ + auto number = to_number(interpreter); + if (interpreter.exception()) + return 0; + return number.to_i32(); } size_t Value::to_size_t() const +{ + ASSERT(type() == Type::Number); + if (is_nan() || as_double() <= 0) + return 0; + return min((double)(i32)as_double(), MAX_ARRAY_LIKE_INDEX); +} + +size_t Value::to_size_t(Interpreter& interpreter) const { if (is_empty()) return 0; - auto number = to_number(); - if (number.is_nan() || number.as_double() <= 0) + auto number = to_number(interpreter); + if (interpreter.exception()) return 0; - return min((double)number.to_i32(), MAX_ARRAY_LIKE_INDEX); + return number.to_size_t(); } -Value greater_than(Interpreter&, Value lhs, Value rhs) +Value greater_than(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() > rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() > rhs_number.as_double()); } -Value greater_than_equals(Interpreter&, Value lhs, Value rhs) +Value greater_than_equals(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() >= rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() >= rhs_number.as_double()); } -Value less_than(Interpreter&, Value lhs, Value rhs) +Value less_than(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() < rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() < rhs_number.as_double()); } -Value less_than_equals(Interpreter&, Value lhs, Value rhs) +Value less_than_equals(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() <= rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() <= rhs_number.as_double()); } -Value bitwise_and(Interpreter&, Value lhs, Value rhs) +Value bitwise_and(Interpreter& interpreter, Value lhs, Value rhs) { - return Value((i32)lhs.to_number().as_double() & (i32)rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value((i32)lhs_number.as_double() & (i32)rhs_number.as_double()); } -Value bitwise_or(Interpreter&, Value lhs, Value rhs) +Value bitwise_or(Interpreter& interpreter, Value lhs, Value rhs) { bool lhs_invalid = lhs.is_undefined() || lhs.is_null() || lhs.is_nan() || lhs.is_infinity(); bool rhs_invalid = rhs.is_undefined() || rhs.is_null() || rhs.is_nan() || rhs.is_infinity(); @@ -294,64 +346,94 @@ Value bitwise_or(Interpreter&, Value lhs, Value rhs) return Value(0); if (lhs_invalid || rhs_invalid) - return lhs_invalid ? rhs.to_number() : lhs.to_number(); + return lhs_invalid ? rhs.to_number(interpreter) : lhs.to_number(interpreter); if (!rhs.is_number() && !lhs.is_number()) return Value(0); - return Value((i32)lhs.to_number().as_double() | (i32)rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value((i32)lhs_number.as_double() | (i32)rhs_number.as_double()); } -Value bitwise_xor(Interpreter&, Value lhs, Value rhs) +Value bitwise_xor(Interpreter& interpreter, Value lhs, Value rhs) { - return Value((i32)lhs.to_number().as_double() ^ (i32)rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value((i32)lhs_number.as_double() ^ (i32)rhs_number.as_double()); } -Value bitwise_not(Interpreter&, Value lhs) +Value bitwise_not(Interpreter& interpreter, Value lhs) { - return Value(~(i32)lhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(~(i32)lhs_number.as_double()); } -Value unary_plus(Interpreter&, Value lhs) +Value unary_plus(Interpreter& interpreter, Value lhs) { - return lhs.to_number(); + return lhs.to_number(interpreter); } -Value unary_minus(Interpreter&, Value lhs) +Value unary_minus(Interpreter& interpreter, Value lhs) { - if (lhs.to_number().is_nan()) + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + if (lhs_number.is_nan()) return js_nan(); - return Value(-lhs.to_number().as_double()); + return Value(-lhs_number.as_double()); } -Value left_shift(Interpreter&, Value lhs, Value rhs) +Value left_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!lhs_number.is_finite_number()) return Value(0); - auto rhs_number = rhs.to_number(); + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!rhs_number.is_finite_number()) return lhs_number; return Value((i32)lhs_number.as_double() << (i32)rhs_number.as_double()); } -Value right_shift(Interpreter&, Value lhs, Value rhs) +Value right_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!lhs_number.is_finite_number()) return Value(0); - auto rhs_number = rhs.to_number(); + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!rhs_number.is_finite_number()) return lhs_number; return Value((i32)lhs_number.as_double() >> (i32)rhs_number.as_double()); } -Value unsigned_right_shift(Interpreter&, Value lhs, Value rhs) +Value unsigned_right_shift(Interpreter& interpreter, Value lhs, Value rhs) { - auto lhs_number = lhs.to_number(); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!lhs_number.is_finite_number()) return Value(0); - auto rhs_number = rhs.to_number(); + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; if (!rhs_number.is_finite_number()) return lhs_number; return Value((unsigned)lhs_number.as_double() >> (i32)rhs_number.as_double()); @@ -379,50 +461,82 @@ Value add(Interpreter& interpreter, Value lhs, Value rhs) return js_string(interpreter, builder.to_string()); } - return Value(lhs_primitive.to_number().as_double() + rhs_primitive.to_number().as_double()); + auto lhs_number = lhs_primitive.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs_primitive.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() + rhs_number.as_double()); } -Value sub(Interpreter&, Value lhs, Value rhs) +Value sub(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() - rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() - rhs_number.as_double()); } -Value mul(Interpreter&, Value lhs, Value rhs) +Value mul(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() * rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() * rhs_number.as_double()); } -Value div(Interpreter&, Value lhs, Value rhs) +Value div(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(lhs.to_number().as_double() / rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(lhs_number.as_double() / rhs_number.as_double()); } -Value mod(Interpreter&, Value lhs, Value rhs) +Value mod(Interpreter& interpreter, Value lhs, Value rhs) { - if (lhs.to_number().is_nan() || rhs.to_number().is_nan()) + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + if (lhs_number.is_nan() || rhs_number.is_nan()) return js_nan(); - - double index = lhs.to_number().as_double(); - double period = rhs.to_number().as_double(); - double trunc = (double)(i32)(index / period); - + auto index = lhs_number.as_double(); + auto period = rhs_number.as_double(); + auto trunc = (double)(i32)(index / period); return Value(index - trunc * period); } -Value exp(Interpreter&, Value lhs, Value rhs) +Value exp(Interpreter& interpreter, Value lhs, Value rhs) { - return Value(pow(lhs.to_number().as_double(), rhs.to_number().as_double())); + auto lhs_number = lhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + auto rhs_number = rhs.to_number(interpreter); + if (interpreter.exception()) + return {}; + return Value(pow(lhs_number.as_double(), rhs_number.as_double())); } Value in(Interpreter& interpreter, Value lhs, Value rhs) { if (!rhs.is_object()) return interpreter.throw_exception("'in' operator must be used on object"); - auto lhs_string = lhs.to_string(interpreter); if (interpreter.exception()) return {}; - return Value(!rhs.as_object().get(lhs_string).is_empty()); } @@ -430,11 +544,9 @@ Value instance_of(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 (!constructor_prototype_property.is_object()) return Value(false); - return Value(lhs.as_object().has_prototype(&constructor_prototype_property.as_object())); } @@ -455,7 +567,7 @@ bool same_value(Interpreter& interpreter, Value lhs, Value rhs) return false; if (lhs.is_negative_zero() && rhs.is_positive_zero()) return false; - return lhs.to_double() == rhs.to_double(); + return lhs.as_double() == rhs.as_double(); } return same_value_non_numeric(interpreter, lhs, rhs); @@ -471,7 +583,7 @@ bool same_value_zero(Interpreter& interpreter, Value lhs, Value rhs) return true; if ((lhs.is_positive_zero() || lhs.is_negative_zero()) && (rhs.is_positive_zero() || rhs.is_negative_zero())) return true; - return lhs.to_double() == rhs.to_double(); + return lhs.as_double() == rhs.as_double(); } return same_value_non_numeric(interpreter, lhs, rhs); @@ -509,7 +621,7 @@ bool strict_eq(Interpreter& interpreter, Value lhs, Value rhs) if (lhs.is_number()) { if (lhs.is_nan() || rhs.is_nan()) return false; - if (lhs.to_double() == rhs.to_double()) + if (lhs.as_double() == rhs.as_double()) return true; if ((lhs.is_positive_zero() || lhs.is_negative_zero()) && (rhs.is_positive_zero() || rhs.is_negative_zero())) return true; @@ -528,16 +640,16 @@ bool abstract_eq(Interpreter& interpreter, Value lhs, Value rhs) return true; if (lhs.is_number() && rhs.is_string()) - return abstract_eq(interpreter, lhs, rhs.to_number()); + return abstract_eq(interpreter, lhs, rhs.to_number(interpreter)); if (lhs.is_string() && rhs.is_number()) - return abstract_eq(interpreter, lhs.to_number(), rhs); + return abstract_eq(interpreter, lhs.to_number(interpreter), rhs); if (lhs.is_boolean()) - return abstract_eq(interpreter, lhs.to_number(), rhs); + return abstract_eq(interpreter, lhs.to_number(interpreter), rhs); if (rhs.is_boolean()) - return abstract_eq(interpreter, lhs, rhs.to_number()); + return abstract_eq(interpreter, lhs, rhs.to_number(interpreter)); if ((lhs.is_string() || lhs.is_number() || lhs.is_symbol()) && rhs.is_object()) return abstract_eq(interpreter, lhs, rhs.to_primitive(interpreter)); diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index ee1d3bbb90..4a04caa627 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -188,11 +188,13 @@ public: PrimitiveString* to_primitive_string(Interpreter&); Value to_primitive(Interpreter&) const; Object* to_object(Interpreter&) const; - bool to_boolean() const; - Value to_number() const; + Value to_number(Interpreter&) const; + double to_double(Interpreter&) const; i32 to_i32() const; - double to_double() const; + i32 to_i32(Interpreter&) const; size_t to_size_t() const; + size_t to_size_t(Interpreter&) const; + bool to_boolean() const; Value value_or(Value fallback) const { diff --git a/Libraries/LibJS/Tests/to-number-exception.js b/Libraries/LibJS/Tests/to-number-exception.js new file mode 100644 index 0000000000..0deec450d5 --- /dev/null +++ b/Libraries/LibJS/Tests/to-number-exception.js @@ -0,0 +1,38 @@ +load("test-common.js"); + +try { + const message = "oops, Value::to_number() failed"; + const o = { toString() { throw new Error(message); } }; + + assertThrowsError(() => { + +o; + }, { + error: Error, + message + }); + + assertThrowsError(() => { + o - 1; + }, { + error: Error, + message + }); + + assertThrowsError(() => { + "foo".charAt(o); + }, { + error: Error, + message + }); + + assertThrowsError(() => { + "bar".repeat(o); + }, { + error: Error, + message + }); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp b/Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp index 34e8dd7b18..194d16361b 100644 --- a/Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp +++ b/Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp @@ -91,8 +91,21 @@ JS::Value CanvasRenderingContext2DWrapper::fill_rect(JS::Interpreter& interprete if (!impl) return {}; auto& arguments = interpreter.call_frame().arguments; - if (arguments.size() >= 4) - impl->fill_rect(arguments[0].to_double(), arguments[1].to_double(), arguments[2].to_double(), arguments[3].to_double()); + if (arguments.size() >= 4) { + auto x = arguments[0].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = arguments[1].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto width = arguments[2].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto height = arguments[3].to_double(interpreter); + if (interpreter.exception()) + return {}; + impl->fill_rect(x, y, width, height); + } return JS::js_undefined(); } @@ -102,8 +115,22 @@ JS::Value CanvasRenderingContext2DWrapper::stroke_rect(JS::Interpreter& interpre if (!impl) return {}; auto& arguments = interpreter.call_frame().arguments; - if (arguments.size() >= 4) - impl->stroke_rect(arguments[0].to_double(), arguments[1].to_double(), arguments[2].to_double(), arguments[3].to_double()); + if (arguments.size() >= 4) { + + auto x = arguments[0].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = arguments[1].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto width = arguments[2].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto height = arguments[3].to_double(interpreter); + if (interpreter.exception()) + return {}; + impl->stroke_rect(x, y, width, height); + } return JS::js_undefined(); } @@ -122,9 +149,12 @@ JS::Value CanvasRenderingContext2DWrapper::draw_image(JS::Interpreter& interpret if (StringView(image_argument->class_name()) != "HTMLImageElementWrapper") return interpreter.throw_exception(String::format("Image is not an HTMLImageElement, it's an %s", image_argument->class_name())); - auto x = arguments[1].to_double(); - auto y = arguments[2].to_double(); - + auto x = arguments[1].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = arguments[2].to_double(interpreter); + if (interpreter.exception()) + return {}; impl->draw_image(static_cast(*image_argument).node(), x, y); return JS::js_undefined(); } @@ -135,8 +165,15 @@ JS::Value CanvasRenderingContext2DWrapper::scale(JS::Interpreter& interpreter) if (!impl) return {}; auto& arguments = interpreter.call_frame().arguments; - if (arguments.size() >= 2) - impl->scale(arguments[0].to_double(), arguments[1].to_double()); + if (arguments.size() >= 2) { + auto sx = arguments[0].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto sy = arguments[1].to_double(interpreter); + if (interpreter.exception()) + return {}; + impl->scale(sx, sy); + } return JS::js_undefined(); } @@ -146,8 +183,15 @@ JS::Value CanvasRenderingContext2DWrapper::translate(JS::Interpreter& interprete if (!impl) return {}; auto& arguments = interpreter.call_frame().arguments; - if (arguments.size() >= 2) - impl->translate(arguments[0].to_double(), arguments[1].to_double()); + if (arguments.size() >= 2) { + auto tx = arguments[0].to_double(interpreter); + if (interpreter.exception()) + return {}; + auto ty = arguments[1].to_double(interpreter); + if (interpreter.exception()) + return {}; + impl->translate(tx, ty); + } return JS::js_undefined(); } @@ -161,12 +205,13 @@ JS::Value CanvasRenderingContext2DWrapper::fill_style_getter(JS::Interpreter& in void CanvasRenderingContext2DWrapper::fill_style_setter(JS::Interpreter& interpreter, JS::Value value) { - if (auto* impl = impl_from(interpreter)) { - auto string = value.to_string(interpreter); - if (interpreter.exception()) - return; - impl->set_fill_style(string); - } + auto* impl = impl_from(interpreter); + if (!impl) + return; + auto string = value.to_string(interpreter); + if (interpreter.exception()) + return; + impl->set_fill_style(string); } JS::Value CanvasRenderingContext2DWrapper::stroke_style_getter(JS::Interpreter& interpreter) @@ -179,12 +224,13 @@ JS::Value CanvasRenderingContext2DWrapper::stroke_style_getter(JS::Interpreter& void CanvasRenderingContext2DWrapper::stroke_style_setter(JS::Interpreter& interpreter, JS::Value value) { - if (auto* impl = impl_from(interpreter)){ - auto string = value.to_string(interpreter); - if (interpreter.exception()) - return; - impl->set_stroke_style(string); - } + auto* impl = impl_from(interpreter); + if (!impl) + return; + auto string = value.to_string(interpreter); + if (interpreter.exception()) + return; + impl->set_stroke_style(string); } JS::Value CanvasRenderingContext2DWrapper::line_width_getter(JS::Interpreter& interpreter) @@ -197,8 +243,13 @@ JS::Value CanvasRenderingContext2DWrapper::line_width_getter(JS::Interpreter& in void CanvasRenderingContext2DWrapper::line_width_setter(JS::Interpreter& interpreter, JS::Value value) { - if (auto* impl = impl_from(interpreter)) - impl->set_line_width(value.to_double()); + auto* impl = impl_from(interpreter); + if (!impl) + return; + auto line_width = value.to_double(interpreter); + if (interpreter.exception()) + return; + impl->set_line_width(line_width); } JS::Value CanvasRenderingContext2DWrapper::begin_path(JS::Interpreter& interpreter) @@ -260,8 +311,12 @@ JS::Value CanvasRenderingContext2DWrapper::move_to(JS::Interpreter& interpreter) auto* impl = impl_from(interpreter); if (!impl) return {}; - double x = interpreter.argument(0).to_double(); - double y = interpreter.argument(1).to_double(); + auto x = interpreter.argument(0).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = interpreter.argument(1).to_double(interpreter); + if (interpreter.exception()) + return {}; impl->move_to(x, y); return JS::js_undefined(); } @@ -271,8 +326,12 @@ JS::Value CanvasRenderingContext2DWrapper::line_to(JS::Interpreter& interpreter) auto* impl = impl_from(interpreter); if (!impl) return {}; - double x = interpreter.argument(0).to_double(); - double y = interpreter.argument(1).to_double(); + auto x = interpreter.argument(0).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = interpreter.argument(1).to_double(interpreter); + if (interpreter.exception()) + return {}; impl->line_to(x, y); return JS::js_undefined(); } @@ -282,10 +341,18 @@ JS::Value CanvasRenderingContext2DWrapper::quadratic_curve_to(JS::Interpreter& i auto* impl = impl_from(interpreter); if (!impl) return {}; - double cx = interpreter.argument(0).to_double(); - double cy = interpreter.argument(1).to_double(); - double x = interpreter.argument(2).to_double(); - double y = interpreter.argument(3).to_double(); + auto cx = interpreter.argument(0).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto cy = interpreter.argument(1).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto x = interpreter.argument(2).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = interpreter.argument(3).to_double(interpreter); + if (interpreter.exception()) + return {}; impl->quadratic_curve_to(cx, cy, x, y); return JS::js_undefined(); } @@ -295,8 +362,12 @@ JS::Value CanvasRenderingContext2DWrapper::create_image_data(JS::Interpreter& in auto* impl = impl_from(interpreter); if (!impl) return {}; - i32 width = interpreter.argument(0).to_i32(); - i32 height = interpreter.argument(1).to_i32(); + auto width = interpreter.argument(0).to_i32(interpreter); + if (interpreter.exception()) + return {}; + auto height = interpreter.argument(1).to_i32(interpreter); + if (interpreter.exception()) + return {}; auto image_data = impl->create_image_data(interpreter.global_object(), width, height); return wrap(interpreter.heap(), *image_data); } @@ -316,8 +387,12 @@ JS::Value CanvasRenderingContext2DWrapper::put_image_data(JS::Interpreter& inter } auto& image_data = static_cast(image_data_object)->impl(); - auto x = interpreter.argument(1).to_double(); - auto y = interpreter.argument(2).to_double(); + auto x = interpreter.argument(1).to_double(interpreter); + if (interpreter.exception()) + return {}; + auto y = interpreter.argument(2).to_double(interpreter); + if (interpreter.exception()) + return {}; impl->put_image_data(image_data, x, y); return JS::js_undefined(); } diff --git a/Libraries/LibWeb/Bindings/WindowObject.cpp b/Libraries/LibWeb/Bindings/WindowObject.cpp index 7a680cdafe..c63169ba15 100644 --- a/Libraries/LibWeb/Bindings/WindowObject.cpp +++ b/Libraries/LibWeb/Bindings/WindowObject.cpp @@ -134,7 +134,10 @@ JS::Value WindowObject::set_interval(JS::Interpreter& interpreter) return {}; if (!callback_object->is_function()) return interpreter.throw_exception("Not a function"); - impl->set_interval(*static_cast(callback_object), arguments[1].to_i32()); + auto interval = arguments[1].to_i32(interpreter); + if (interpreter.exception()) + return {}; + impl->set_interval(*static_cast(callback_object), interval); return JS::js_undefined(); } @@ -153,8 +156,11 @@ JS::Value WindowObject::set_timeout(JS::Interpreter& interpreter) return interpreter.throw_exception("Not a function"); i32 interval = 0; - if (interpreter.argument_count() >= 2) - interval = arguments[1].to_i32(); + if (interpreter.argument_count() >= 2) { + interval = arguments[1].to_i32(interpreter); + if (interpreter.exception()) + return {}; + } impl->set_timeout(*static_cast(callback_object), interval); return JS::js_undefined(); @@ -184,7 +190,10 @@ JS::Value WindowObject::cancel_animation_frame(JS::Interpreter& interpreter) auto& arguments = interpreter.call_frame().arguments; if (arguments.size() < 1) return {}; - impl->cancel_animation_frame(arguments[0].to_i32()); + auto id = arguments[0].to_i32(interpreter); + if (interpreter.exception()) + return {}; + impl->cancel_animation_frame(id); return JS::js_undefined(); } diff --git a/Userland/js.cpp b/Userland/js.cpp index ad273e4fc3..b7a84b4fae 100644 --- a/Userland/js.cpp +++ b/Userland/js.cpp @@ -328,9 +328,10 @@ JS::Value ReplObject::exit_interpreter(JS::Interpreter& interpreter) { if (!interpreter.argument_count()) exit(0); - int exit_code = interpreter.argument(0).to_number().as_double(); - exit(exit_code); - return JS::js_undefined(); + auto exit_code = interpreter.argument(0).to_number(interpreter); + if (interpreter.exception()) + return {}; + exit(exit_code.as_double()); } JS::Value ReplObject::repl_help(JS::Interpreter&)