LibJS: Rewrite Math.{max, min} to handle exceptions and NaNs properly

The specification requires that we immediately return a NaN during the
iteration over the arguments if one is encountered. It 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 NaN
early return.
This commit is contained in:
Idan Horowitz 2021-06-05 02:05:06 +03:00 committed by Linus Groh
parent 24ffe91b16
commit 7507999230
Notes: sideshowbarker 2024-07-18 16:50:50 +09:00

View file

@ -153,38 +153,42 @@ JS_DEFINE_NATIVE_FUNCTION(MathObject::round)
JS_DEFINE_NATIVE_FUNCTION(MathObject::max)
{
if (!vm.argument_count())
return js_negative_infinity();
auto max = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
for (size_t i = 1; i < vm.argument_count(); ++i) {
auto cur = vm.argument(i).to_number(global_object);
Vector<Value> coerced;
for (size_t i = 0; i < vm.argument_count(); ++i) {
auto number = vm.argument(i).to_number(global_object);
if (vm.exception())
return {};
if ((max.is_negative_zero() && cur.is_positive_zero()) || cur.as_double() > max.as_double())
max = cur;
coerced.append(number);
}
return max;
auto highest = js_negative_infinity();
for (auto& number : coerced) {
if (number.is_nan())
return js_nan();
if ((number.is_positive_zero() && highest.is_negative_zero()) || number.as_double() > highest.as_double())
highest = number;
}
return highest;
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::min)
{
if (!vm.argument_count())
return js_infinity();
auto min = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
for (size_t i = 1; i < vm.argument_count(); ++i) {
auto cur = vm.argument(i).to_number(global_object);
Vector<Value> coerced;
for (size_t i = 0; i < vm.argument_count(); ++i) {
auto number = vm.argument(i).to_number(global_object);
if (vm.exception())
return {};
if ((min.is_positive_zero() && cur.is_negative_zero()) || cur.as_double() < min.as_double())
min = cur;
coerced.append(number);
}
return min;
auto lowest = js_infinity();
for (auto& number : coerced) {
if (number.is_nan())
return js_nan();
if ((number.is_negative_zero() && lowest.is_positive_zero()) || number.as_double() < lowest.as_double())
lowest = number;
}
return lowest;
}
JS_DEFINE_NATIVE_FUNCTION(MathObject::trunc)