Commit 62d1f782 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Fix throwing in Exponentiate()

When the multiplication steps fail, they have already thrown an
exception internally, so we should not throw another.
The power-of-two fast path erroneously did not throw at all for
a few input values.

Bug: chromium:818277
Change-Id: If90f6aa3e77fc72e3434daca3b898c77739933ab
Reviewed-on: https://chromium-review.googlesource.com/947254
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51711}
parent a2629d03
...@@ -341,8 +341,10 @@ MaybeHandle<BigInt> BigInt::Exponentiate(Handle<BigInt> base, ...@@ -341,8 +341,10 @@ MaybeHandle<BigInt> BigInt::Exponentiate(Handle<BigInt> base,
if (base->length() == 1 && base->digit(0) == 2) { if (base->length() == 1 && base->digit(0) == 2) {
// Fast path for 2^n. // Fast path for 2^n.
int needed_digits = 1 + (n / kDigitBits); int needed_digits = 1 + (n / kDigitBits);
Handle<MutableBigInt> result = Handle<MutableBigInt> result;
MutableBigInt::New(isolate, needed_digits).ToHandleChecked(); if (!MutableBigInt::New(isolate, needed_digits).ToHandle(&result)) {
return MaybeHandle<BigInt>();
}
result->InitializeDigits(needed_digits); result->InitializeDigits(needed_digits);
// All bits are zero. Now set the n-th bit. // All bits are zero. Now set the n-th bit.
digit_t msd = static_cast<digit_t>(1) << (n % kDigitBits); digit_t msd = static_cast<digit_t>(1) << (n % kDigitBits);
...@@ -357,18 +359,14 @@ MaybeHandle<BigInt> BigInt::Exponentiate(Handle<BigInt> base, ...@@ -357,18 +359,14 @@ MaybeHandle<BigInt> BigInt::Exponentiate(Handle<BigInt> base,
if (n & 1) result = base; if (n & 1) result = base;
n >>= 1; n >>= 1;
for (; n != 0; n >>= 1) { for (; n != 0; n >>= 1) {
if (!Multiply(running_square, running_square).ToHandle(&running_square)) { MaybeHandle<BigInt> maybe_result = Multiply(running_square, running_square);
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), if (!maybe_result.ToHandle(&running_square)) return maybe_result;
BigInt);
}
if (n & 1) { if (n & 1) {
if (result.is_null()) { if (result.is_null()) {
result = running_square; result = running_square;
} else { } else {
if (!Multiply(result, running_square).ToHandle(&result)) { maybe_result = Multiply(result, running_square);
THROW_NEW_ERROR( if (!maybe_result.ToHandle(&result)) return maybe_result;
isolate, NewRangeError(MessageTemplate::kBigIntTooBig), BigInt);
}
} }
} }
} }
......
...@@ -18,3 +18,18 @@ assertEquals(0n, 5n % -1n); ...@@ -18,3 +18,18 @@ assertEquals(0n, 5n % -1n);
assertEquals(0n, -5n % -1n); assertEquals(0n, -5n % -1n);
assertTrue(0n === 0n); assertTrue(0n === 0n);
// crbug.com/818277: Must throw without DCHECK failures.
// In order to run acceptably fast in Debug mode, this test assumes that
// we allow at least 2 billion bits in a BigInt.
var close_to_limit = 2n ** 2000000000n;
assertThrows(() => close_to_limit ** 100n, RangeError);
// Check boundary conditions of the power-of-two fast path.
// The following "max" constants are just under BigInt::kMaxLengthBits
// and replicate the computation of that constant.
var kMaxInt = 2n ** 31n - 1n;
var max64 = kMaxInt - 64n - 2n;
var max32 = kMaxInt - 32n - 2n;
// Platform independence trick: at least one of the two operations will throw!
assertThrows(() => { var a = 2n ** max32; var b = 2n ** max64; }, RangeError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment