From 57a52094d1ee6072f853cd82a40bf3c38986467e Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sat, 5 Jun 2021 03:20:00 +0300 Subject: [PATCH] LibJS: Rewrite Math.hypot to handle exceptions, NaNs, Infinity properly The specification requires that we immediately return Infinity during the iteration over the arguments if positive or negative infinity is encountered, and return a NaN if it is encountered and no Infinity was found. The specification also requires all arguments to be coerced into numbers before the operation starts, or else a number conversion exception could be missed due to the Infinity/NaN early return. --- .../Libraries/LibJS/Runtime/MathObject.cpp | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/MathObject.cpp b/Userland/Libraries/LibJS/Runtime/MathObject.cpp index b005d0fff6..10c66f6efd 100644 --- a/Userland/Libraries/LibJS/Runtime/MathObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/MathObject.cpp @@ -473,20 +473,33 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::fround) JS_DEFINE_NATIVE_FUNCTION(MathObject::hypot) { - if (!vm.argument_count()) - return Value(0); - - auto hypot = vm.argument(0).to_number(global_object); - if (vm.exception()) - return {}; - hypot = Value(hypot.as_double() * hypot.as_double()); - for (size_t i = 1; i < vm.argument_count(); ++i) { - auto cur = vm.argument(i).to_number(global_object); + Vector coerced; + for (size_t i = 0; i < vm.argument_count(); ++i) { + auto number = vm.argument(i).to_number(global_object); if (vm.exception()) return {}; - hypot = Value(hypot.as_double() + cur.as_double() * cur.as_double()); + coerced.append(number); } - return Value(::sqrt(hypot.as_double())); + + for (auto& number : coerced) { + if (number.is_positive_infinity() || number.is_negative_infinity()) + return js_infinity(); + } + + auto only_zero = true; + double sum_of_squares = 0; + for (auto& number : coerced) { + if (number.is_nan() || number.is_positive_infinity()) + return number; + if (number.is_negative_infinity()) + return js_infinity(); + if (!number.is_positive_zero() && !number.is_negative_zero()) + only_zero = false; + sum_of_squares += number.as_double() * number.as_double(); + } + if (only_zero) + return Value(0); + return Value(::sqrt(sum_of_squares)); } JS_DEFINE_NATIVE_FUNCTION(MathObject::imul)