Skip to content

Commit baaf8c9

Browse files
committed
Fix #4870: Handle large (pos and neg) counts in BigInteger.shift{Left,Right}.
1 parent 3fe1c30 commit baaf8c9

File tree

3 files changed

+23
-4
lines changed

3 files changed

+23
-4
lines changed

javalib/src/main/scala/java/math/BigInteger.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ object BigInteger {
130130
throw new IllegalArgumentException(errorMessage)
131131
}
132132

133+
private[math] def checkRangeBasedOnIntArrayLength(byteLength: Int): Unit = {
134+
if (byteLength < 0 || byteLength >= ((Int.MaxValue + 1) >>> 5))
135+
throw new ArithmeticException("BigInteger would overflow supported range")
136+
}
137+
133138
@inline
134139
private[math] final class QuotAndRem(val quot: BigInteger, val rem: BigInteger) {
135140
def toArray(): Array[BigInteger] = Array[BigInteger](quot, rem)
@@ -668,13 +673,13 @@ class BigInteger extends Number with Comparable[BigInteger] {
668673
def shiftLeft(n: Int): BigInteger = {
669674
if (n == 0 || sign == 0) this
670675
else if (n > 0) BitLevel.shiftLeft(this, n)
671-
else BitLevel.shiftRight(this, -n)
676+
else BitLevel.shiftRight(this, -n) // -n is interpreted as unsigned, so MinValue is fine
672677
}
673678

674679
def shiftRight(n: Int): BigInteger = {
675680
if (n == 0 || sign == 0) this
676681
else if (n > 0) BitLevel.shiftRight(this, n)
677-
else BitLevel.shiftLeft(this, -n)
682+
else BitLevel.shiftLeft(this, -n) // -n is interpreted as unsigned, so MinValue is fine
678683
}
679684

680685
def signum(): Int = sign

javalib/src/main/scala/java/math/BitLevel.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,11 @@ private[math] object BitLevel {
220220
* @return
221221
*/
222222
def shiftLeft(source: BigInteger, count: Int): BigInteger = {
223-
val intCount: Int = count >> 5
223+
val intCount: Int = count >>> 5 // interpret count as unsigned to deal with -MinValue
224224
val andCount: Int = count & 31
225225
val offset = if (andCount == 0) 0 else 1
226226
val resLength: Int = source.numberLength + intCount + offset
227+
BigInteger.checkRangeBasedOnIntArrayLength(resLength)
227228
val resDigits = new Array[Int](resLength)
228229
shiftLeft(resDigits, source.digits, intCount, andCount)
229230
val result = new BigInteger(source.sign, resLength, resDigits)
@@ -298,7 +299,7 @@ private[math] object BitLevel {
298299
* @return
299300
*/
300301
def shiftRight(source: BigInteger, count: Int): BigInteger = {
301-
val intCount: Int = count >> 5
302+
val intCount: Int = count >>> 5 // interpret count as unsigned to deal with -MinValue
302303
val andCount: Int = count & 31 // count of remaining bits
303304

304305
if (intCount >= source.numberLength) {

test-suite/shared/src/test/scala/org/scalajs/testsuite/javalib/math/BigIntegerOperateBitsTest.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,19 @@ class BigIntegerOperateBitsTest {
10291029
assertEquals(-1, result.signum())
10301030
}
10311031

1032+
@Test def testShiftsWithLargeCounts_Issue4870(): Unit = {
1033+
val aNumber = new BigInteger(-1, Array[Byte](0, -82, 127, 15, 76, -97, 13, 30, 30))
1034+
1035+
assertThrows(classOf[ArithmeticException], aNumber.shiftLeft(Int.MaxValue))
1036+
assertThrows(classOf[ArithmeticException], aNumber.shiftRight(Int.MinValue))
1037+
assertThrows(classOf[ArithmeticException], aNumber.shiftRight(Int.MinValue + 1))
1038+
1039+
val minusOne = BigInteger.ONE.negate()
1040+
assertEquals(minusOne, aNumber.shiftRight(Int.MaxValue))
1041+
assertEquals(minusOne, aNumber.shiftLeft(Int.MinValue))
1042+
assertEquals(minusOne, aNumber.shiftLeft(Int.MinValue + 1))
1043+
}
1044+
10321045
@Test def testTestBitException(): Unit = {
10331046
val aBytes = Array[Byte](-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26)
10341047
val aSign = 1

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy