summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-05-18 00:28:00 +0100
committerAndreas Kling <kling@serenityos.org>2020-05-18 09:39:55 +0200
commit476094922b6dbbc252a076aecca9cc0d172e540e (patch)
treedadd0976793ea60541d74c82f3531ab6b38a4dc8 /Libraries
parent1a1394f7a2f17bb0631cc4aaaa9c78f0cf700312 (diff)
downloadserenity-476094922b6dbbc252a076aecca9cc0d172e540e.zip
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.
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/AST.cpp5
-rw-r--r--Libraries/LibJS/Runtime/Array.cpp4
-rw-r--r--Libraries/LibJS/Runtime/ArrayPrototype.cpp27
-rw-r--r--Libraries/LibJS/Runtime/ErrorPrototype.cpp12
-rw-r--r--Libraries/LibJS/Runtime/FunctionPrototype.cpp6
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.cpp13
-rw-r--r--Libraries/LibJS/Runtime/MathObject.cpp59
-rw-r--r--Libraries/LibJS/Runtime/NumberConstructor.cpp15
-rw-r--r--Libraries/LibJS/Runtime/ReflectObject.cpp11
-rw-r--r--Libraries/LibJS/Runtime/StringPrototype.cpp52
-rw-r--r--Libraries/LibJS/Runtime/Uint8ClampedArray.cpp5
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp248
-rw-r--r--Libraries/LibJS/Runtime/Value.h8
-rw-r--r--Libraries/LibJS/Tests/to-number-exception.js38
-rw-r--r--Libraries/LibWeb/Bindings/CanvasRenderingContext2DWrapper.cpp149
-rw-r--r--Libraries/LibWeb/Bindings/WindowObject.cpp17
16 files changed, 486 insertions, 183 deletions
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<RangeError>("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<ssize_t>(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<TypeError>("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<i32>(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<RangeError>("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<i32>(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 <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PrimitiveString.h>
-#include <LibJS/Runtime/Symbol.h>
#include <LibJS/Runtime/StringObject.h>
+#include <LibJS/Runtime/Symbol.h>
#include <LibJS/Runtime/SymbolObject.h>
#include <LibJS/Runtime/Value.h>
#include <math.h>
@@ -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();
}
+double Value::to_double(Interpreter& interpreter) const
+{
+ auto number = to_number(interpreter);
+ if (interpreter.exception())
+ return 0;
+ return number.as_double();
+}
+
i32 Value::to_i32() const
{
- return static_cast<i32>(to_number().as_double());
+ return static_cast<i32>(as_double());
}
-double Value::to_double() const
+i32 Value::to_i32(Interpreter& interpreter) const
{
- return to_number().as_double();
+ 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<TypeError>("'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<JS::TypeError>(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<const HTMLImageElementWrapper&>(*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<ImageDataWrapper*>(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<JS::TypeError>("Not a function");
- impl->set_interval(*static_cast<JS::Function*>(callback_object), arguments[1].to_i32());
+ auto interval = arguments[1].to_i32(interpreter);
+ if (interpreter.exception())
+ return {};
+ impl->set_interval(*static_cast<JS::Function*>(callback_object), interval);
return JS::js_undefined();
}
@@ -153,8 +156,11 @@ JS::Value WindowObject::set_timeout(JS::Interpreter& interpreter)
return interpreter.throw_exception<JS::TypeError>("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<JS::Function*>(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();
}