From 11138f5c1ffbb039285e2bbba39d0bb8319408cb Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Tue, 16 Mar 2021 20:34:40 +0100 Subject: [PATCH] LibJS: Throw RangeError on BigInt division/modulo by zero https://tc39.es/ecma262/#sec-numeric-types-bigint-divide https://tc39.es/ecma262/#sec-numeric-types-bigint-remainder --- Userland/Libraries/LibJS/Runtime/ErrorTypes.h | 1 + Userland/Libraries/LibJS/Runtime/Value.cpp | 28 +++++++++++++------ .../Tests/builtins/BigInt/bigint-basic.js | 9 ++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index 1d4157855b..58bb2f2929 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -43,6 +43,7 @@ M(Convert, "Cannot convert {} to {}") \ M(ConvertUndefinedToObject, "Cannot convert undefined to object") \ M(DescChangeNonConfigurable, "Cannot change attributes of non-configurable property '{}'") \ + M(DivisionByZero, "Division by zero") \ M(FunctionArgsNotObject, "Argument array must be an object") \ M(InOperatorWithObject, "'in' operator must be used on an object") \ M(InstanceOfOperatorBadPrototype, "'prototype' property of {} is not an object") \ diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 34d96e2a29..e29d40aa40 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -882,27 +882,34 @@ Value mul(GlobalObject& global_object, Value lhs, Value rhs) Value div(GlobalObject& global_object, Value lhs, Value rhs) { + auto& vm = global_object.vm(); auto lhs_numeric = lhs.to_numeric(global_object.global_object()); - if (global_object.vm().exception()) + if (vm.exception()) return {}; auto rhs_numeric = rhs.to_numeric(global_object.global_object()); - if (global_object.vm().exception()) + if (vm.exception()) return {}; if (both_number(lhs_numeric, rhs_numeric)) return Value(lhs_numeric.as_double() / rhs_numeric.as_double()); - if (both_bigint(lhs_numeric, rhs_numeric)) + if (both_bigint(lhs_numeric, rhs_numeric)) { + if (rhs_numeric.as_bigint().big_integer() == BIGINT_ZERO) { + vm.throw_exception(global_object, ErrorType::DivisionByZero); + return {}; + } return js_bigint(global_object.heap(), lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).quotient); - global_object.vm().throw_exception(global_object.global_object(), ErrorType::BigIntBadOperatorOtherType, "division"); + } + vm.throw_exception(global_object.global_object(), ErrorType::BigIntBadOperatorOtherType, "division"); return {}; } Value mod(GlobalObject& global_object, Value lhs, Value rhs) { + auto& vm = global_object.vm(); auto lhs_numeric = lhs.to_numeric(global_object.global_object()); - if (global_object.vm().exception()) + if (vm.exception()) return {}; auto rhs_numeric = rhs.to_numeric(global_object.global_object()); - if (global_object.vm().exception()) + if (vm.exception()) return {}; if (both_number(lhs_numeric, rhs_numeric)) { if (lhs_numeric.is_nan() || rhs_numeric.is_nan()) @@ -912,9 +919,14 @@ Value mod(GlobalObject& global_object, Value lhs, Value rhs) auto trunc = (double)(i32)(index / period); return Value(index - trunc * period); } - if (both_bigint(lhs_numeric, rhs_numeric)) + if (both_bigint(lhs_numeric, rhs_numeric)) { + if (rhs_numeric.as_bigint().big_integer() == BIGINT_ZERO) { + vm.throw_exception(global_object, ErrorType::DivisionByZero); + return {}; + } return js_bigint(global_object.heap(), lhs_numeric.as_bigint().big_integer().divided_by(rhs_numeric.as_bigint().big_integer()).remainder); - global_object.vm().throw_exception(global_object.global_object(), ErrorType::BigIntBadOperatorOtherType, "modulo"); + } + vm.throw_exception(global_object.global_object(), ErrorType::BigIntBadOperatorOtherType, "modulo"); return {}; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js index 244bc44a92..eb96764d4f 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js +++ b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js @@ -87,4 +87,13 @@ describe("errors", () => { +123n; }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number"); }); + + test("division by zero", () => { + expect(() => { + 1n / 0n; + }).toThrowWithMessage(RangeError, "Division by zero"); + expect(() => { + 1n % 0n; + }).toThrowWithMessage(RangeError, "Division by zero"); + }); });