Open Bug 2043295 Opened 2 months ago Updated 2 months ago

Differential behavior: BigInt division throws RangeError on max-size dividend due to over-allocation in absoluteLeftShiftAlwaysCopy

Categories

(Core :: JavaScript Engine, defect, P3)

x86_64
Linux
defect

Tracking

()

People

(Reporter: decoder, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: ai-involved, testcase)

Attachments

(1 file)

Summary

BigInt::absoluteLeftShiftAlwaysCopy unconditionally allocates n + 1 digits when called with LeftShiftMode::AlwaysAddOneDigit. When the dividend is already at MaxDigitLength, the internal temporary exceeds the allocation limit and the engine throws RangeError: BigInt is too large to allocate, even though the final quotient is well within the limit. V8 computes the correct result.

Root Cause

In js/src/vm/BigIntType.cpp:805, resultLength is computed as n + 1 for AlwaysAddOneDigit mode. When this is called from absoluteDivWithBigIntDivisor (line 911) with a max-size dividend (n == MaxDigitLength), createUninitialized(cx, MaxDigitLength + 1, ...) at line 806 fails because it exceeds the allocation limit check at line 141.

The over-allocation is an internal implementation detail of the Knuth division normalization step — the final result (quotient) is much smaller than MaxDigitLength, so the operation should succeed.

Reproduction

Testcase: poc.js

const maxBitLength = 1024n * 1024n;
const x = 1n << (maxBitLength - 1n);
const y = 1n << 64n;

const q = x / y;
const expected = 1n << (maxBitLength - 65n);

if (q !== expected) {
  throw new Error("wrong quotient");
}

print("ok");

SpiderMonkey (mozilla-central 20260521-b754e06486cf, fuzzing-asan-opt):

$ dist/bin/js --fuzzing-safe poc.js
poc.js:5:15 RangeError: BigInt is too large to allocate

V8:

$ d8 poc.js
ok

No special prefs or flags are required beyond --fuzzing-safe (used only for fuzzing stability, not required to reproduce).

Suggested Fix

Either:

  1. Increase the internal allocation limit for temporaries in division (allow MaxDigitLength + 1 for internal intermediate results), or
  2. Handle the max-size dividend case in absoluteDivWithBigIntDivisor by special-casing when shift == 0 to avoid the extra digit allocation, or
  3. Use a separate internal limit for transient allocations that is slightly larger than the public MaxDigitLength.
Attached file poc.js
Group: javascript-core-security
Keywords: sec-audit
See Also: → 2043294
Blocks: sm-runtime
Severity: -- → S4
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: