changeset 10542:0734e1584d9d

6910473: java.math.BigInteger.bitLength() may return negative "int" on large numbers 8021203: BigInteger.doubleValue/floatValue returns 0.0 instead of Infinity 8021204: Constructor BigInteger(String val, int radix) doesn't detect overflow 8022780: Incorrect BigInteger division because of MutableBigInteger.bitLength() overflow Summary: Prevent construction of overflowed BigIntegers. Reviewed-by: bpb, darcy, psandoz Contributed-by: Dmitry Nadezhin <dmitry.nadezhin@oracle.com>
author bpb
date Wed, 30 Oct 2013 17:45:12 -0700
parents e8894e3224d9
children 1ea1b24c1a04
files src/share/classes/java/math/BigInteger.java src/share/classes/java/math/MutableBigInteger.java test/java/math/BigInteger/BitLengthOverflow.java test/java/math/BigInteger/DivisionOverflow.java test/java/math/BigInteger/DoubleValueOverflow.java test/java/math/BigInteger/ExtremeShiftingTests.java test/java/math/BigInteger/StringConstructorOverflow.java test/java/math/BigInteger/SymmetricRangeTests.java
diffstat 8 files changed, 1063 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/math/BigInteger.java	Wed Oct 30 17:27:25 2013 -0700
+++ b/src/share/classes/java/math/BigInteger.java	Wed Oct 30 17:45:12 2013 -0700
@@ -97,6 +97,21 @@
  * {@code NullPointerException} when passed
  * a null object reference for any input parameter.
  *
+ * BigInteger must support values in the range
+ * -2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive) to
+ * +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive)
+ * and may support values outside of that range.
+ *
+ * The range of probable prime values is limited and may be less than
+ * the full supported positive range of {@code BigInteger}.
+ * The range must be at least 1 to 2<sup>500000000</sup>.
+ *
+ * @implNote
+ * BigInteger constructors and operations throw {@code ArithmeticException} when
+ * the result is out of the supported range of
+ * -2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive) to
+ * +2<sup>{@code Integer.MAX_VALUE}</sup> (exclusive).
+ *
  * @see     BigDecimal
  * @author  Josh Bloch
  * @author  Michael McCloskey
@@ -183,6 +198,18 @@
     final static long LONG_MASK = 0xffffffffL;
 
     /**
+     * This constant limits {@code mag.length} of BigIntegers to the supported
+     * range.
+     */
+    private static final int MAX_MAG_LENGTH = Integer.MAX_VALUE / Integer.SIZE + 1; // (1 << 26)
+
+    /**
+     * Bit lengths larger than this constant can cause overflow in searchLen
+     * calculation and in BitSieve.singleSearch method.
+     */
+    private static final  int PRIME_SEARCH_BIT_LENGTH_LIMIT = 500000000;
+
+    /**
      * The threshold value for using Karatsuba multiplication.  If the number
      * of ints in both mag arrays are greater than this number, then
      * Karatsuba multiplication will be used.   This value is found
@@ -256,6 +283,9 @@
             mag = stripLeadingZeroBytes(val);
             signum = (mag.length == 0 ? 0 : 1);
         }
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /**
@@ -275,6 +305,9 @@
             mag = trustedStripLeadingZeroInts(val);
             signum = (mag.length == 0 ? 0 : 1);
         }
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /**
@@ -306,6 +339,9 @@
                 throw(new NumberFormatException("signum-magnitude mismatch"));
             this.signum = signum;
         }
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /**
@@ -327,6 +363,9 @@
                 throw(new NumberFormatException("signum-magnitude mismatch"));
             this.signum = signum;
         }
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /**
@@ -359,17 +398,20 @@
         int sign = 1;
         int index1 = val.lastIndexOf('-');
         int index2 = val.lastIndexOf('+');
-        if ((index1 + index2) <= -1) {
-            // No leading sign character or at most one leading sign character
-            if (index1 == 0 || index2 == 0) {
-                cursor = 1;
-                if (len == 1)
-                    throw new NumberFormatException("Zero length BigInteger");
+        if (index1 >= 0) {
+            if (index1 != 0 || index2 >= 0) {
+                throw new NumberFormatException("Illegal embedded sign character");
             }
-            if (index1 == 0)
-                sign = -1;
-        } else
-            throw new NumberFormatException("Illegal embedded sign character");
+            sign = -1;
+            cursor = 1;
+        } else if (index2 >= 0) {
+            if (index2 != 0) {
+                throw new NumberFormatException("Illegal embedded sign character");
+            }
+            cursor = 1;
+        }
+        if (cursor == len)
+            throw new NumberFormatException("Zero length BigInteger");
 
         // Skip leading zeros and compute number of digits in magnitude
         while (cursor < len &&
@@ -388,8 +430,11 @@
 
         // Pre-allocate array of expected size. May be too large but can
         // never be too small. Typically exact.
-        int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);
-        int numWords = (numBits + 31) >>> 5;
+        long numBits = ((numDigits * bitsPerDigit[radix]) >>> 10) + 1;
+        if (numBits + 31 >= (1L << 32)) {
+            reportOverflow();
+        }
+        int numWords = (int) (numBits + 31) >>> 5;
         int[] magnitude = new int[numWords];
 
         // Process first (potentially short) digit group
@@ -413,6 +458,9 @@
         }
         // Required for cases where the array was overallocated.
         mag = trustedStripLeadingZeroInts(magnitude);
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /*
@@ -439,8 +487,11 @@
         if (len < 10) {
             numWords = 1;
         } else {
-            int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1);
-            numWords = (numBits + 31) >>> 5;
+            long numBits = ((numDigits * bitsPerDigit[10]) >>> 10) + 1;
+            if (numBits + 31 >= (1L << 32)) {
+                reportOverflow();
+            }
+            numWords = (int) (numBits + 31) >>> 5;
         }
         int[] magnitude = new int[numWords];
 
@@ -456,6 +507,9 @@
             destructiveMulAdd(magnitude, intRadix[10], groupVal);
         }
         mag = trustedStripLeadingZeroInts(magnitude);
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     // Create an integer with the digits between the two indexes
@@ -575,7 +629,7 @@
      *         this constructor is proportional to the value of this parameter.
      * @param  rnd source of random bits used to select candidates to be
      *         tested for primality.
-     * @throws ArithmeticException {@code bitLength < 2}.
+     * @throws ArithmeticException {@code bitLength < 2} or {@code bitLength} is too large.
      * @see    #bitLength()
      */
     public BigInteger(int bitLength, int certainty, Random rnd) {
@@ -607,7 +661,7 @@
      * @param  rnd source of random bits used to select candidates to be
      *         tested for primality.
      * @return a BigInteger of {@code bitLength} bits that is probably prime
-     * @throws ArithmeticException {@code bitLength < 2}.
+     * @throws ArithmeticException {@code bitLength < 2} or {@code bitLength} is too large.
      * @see    #bitLength()
      * @since 1.4
      */
@@ -677,7 +731,7 @@
         p.mag[p.mag.length-1] &= 0xfffffffe;
 
         // Use a sieve length likely to contain the next prime number
-        int searchLen = (bitLength / 20) * 64;
+        int searchLen = getPrimeSearchLen(bitLength);
         BitSieve searchSieve = new BitSieve(p, searchLen);
         BigInteger candidate = searchSieve.retrieve(p, certainty, rnd);
 
@@ -701,7 +755,7 @@
     *
     * @return the first integer greater than this {@code BigInteger} that
     *         is probably prime.
-    * @throws ArithmeticException {@code this < 0}.
+    * @throws ArithmeticException {@code this < 0} or {@code this} is too large.
     * @since 1.5
     */
     public BigInteger nextProbablePrime() {
@@ -750,7 +804,7 @@
             result = result.subtract(ONE);
 
         // Looking for the next large prime
-        int searchLen = (result.bitLength() / 20) * 64;
+        int searchLen = getPrimeSearchLen(result.bitLength());
 
         while (true) {
            BitSieve searchSieve = new BitSieve(result, searchLen);
@@ -762,6 +816,13 @@
         }
     }
 
+    private static int getPrimeSearchLen(int bitLength) {
+        if (bitLength > PRIME_SEARCH_BIT_LENGTH_LIMIT + 1) {
+            throw new ArithmeticException("Prime search implementation restriction on bitLength");
+        }
+        return bitLength / 20 * 64;
+    }
+
     /**
      * Returns {@code true} if this BigInteger is probably prime,
      * {@code false} if it's definitely composite.
@@ -965,6 +1026,9 @@
     BigInteger(int[] magnitude, int signum) {
         this.signum = (magnitude.length == 0 ? 0 : signum);
         this.mag = magnitude;
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
     }
 
     /**
@@ -974,6 +1038,25 @@
     private BigInteger(byte[] magnitude, int signum) {
         this.signum = (magnitude.length == 0 ? 0 : signum);
         this.mag = stripLeadingZeroBytes(magnitude);
+        if (mag.length >= MAX_MAG_LENGTH) {
+            checkRange();
+        }
+    }
+
+    /**
+     * Throws an {@code ArithmeticException} if the {@code BigInteger} would be
+     * out of the supported range.
+     *
+     * @throws ArithmeticException if {@code this} exceeds the supported range.
+     */
+    private void checkRange() {
+        if (mag.length > MAX_MAG_LENGTH || mag.length == MAX_MAG_LENGTH && mag[0] < 0) {
+            reportOverflow();
+        }
+    }
+
+    private static void reportOverflow() {
+        throw new ArithmeticException("BigInteger would overflow supported range");
     }
 
     //Static Factory Methods
@@ -2073,6 +2156,10 @@
         // The remaining part can then be exponentiated faster.  The
         // powers of two will be multiplied back at the end.
         int powersOfTwo = partToSquare.getLowestSetBit();
+        long bitsToShift = (long)powersOfTwo * exponent;
+        if (bitsToShift > Integer.MAX_VALUE) {
+            reportOverflow();
+        }
 
         int remainingBits;
 
@@ -2126,11 +2213,10 @@
 
             // Multiply back the powers of two (quickly, by shifting left)
             if (powersOfTwo > 0) {
-                int bitsToShift = powersOfTwo*exponent;
                 if (bitsToShift + scaleFactor <= 62) { // Fits in long?
                     return valueOf((result << bitsToShift) * newSign);
                 } else {
-                    return valueOf(result*newSign).shiftLeft(bitsToShift);
+                    return valueOf(result*newSign).shiftLeft((int) bitsToShift);
                 }
             }
             else {
@@ -2375,8 +2461,17 @@
             BigInteger y1 = m2.modInverse(m1);
             BigInteger y2 = m1.modInverse(m2);
 
-            result = a1.multiply(m2).multiply(y1).add
-                     (a2.multiply(m1).multiply(y2)).mod(m);
+            if (m.mag.length < MAX_MAG_LENGTH / 2) {
+                result = a1.multiply(m2).multiply(y1).add(a2.multiply(m1).multiply(y2)).mod(m);
+            } else {
+                MutableBigInteger t1 = new MutableBigInteger();
+                new MutableBigInteger(a1.multiply(m2)).multiply(new MutableBigInteger(y1), t1);
+                MutableBigInteger t2 = new MutableBigInteger();
+                new MutableBigInteger(a2.multiply(m1)).multiply(new MutableBigInteger(y2), t2);
+                t1.add(t2);
+                MutableBigInteger q = new MutableBigInteger();
+                result = t1.divide(new MutableBigInteger(m), q).toBigInteger();
+            }
         }
 
         return (invertResult ? result.modInverse(m) : result);
@@ -2797,27 +2892,31 @@
      *
      * @param  n shift distance, in bits.
      * @return {@code this << n}
-     * @throws ArithmeticException if the shift distance is {@code
-     *         Integer.MIN_VALUE}.
      * @see #shiftRight
      */
     public BigInteger shiftLeft(int n) {
         if (signum == 0)
             return ZERO;
-        if (n == 0)
+        if (n > 0) {
+            return new BigInteger(shiftLeft(mag, n), signum);
+        } else if (n == 0) {
             return this;
-        if (n < 0) {
-            if (n == Integer.MIN_VALUE) {
-                throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
-            } else {
-                return shiftRight(-n);
-            }
+        } else {
+            // Possible int overflow in (-n) is not a trouble,
+            // because shiftRightImpl considers its argument unsigned
+            return shiftRightImpl(-n);
         }
-        int[] newMag = shiftLeft(mag, n);
-
-        return new BigInteger(newMag, signum);
     }
 
+    /**
+     * Returns a magnitude array whose value is {@code (mag << n)}.
+     * The shift distance, {@code n}, is considered unnsigned.
+     * (Computes <tt>this * 2<sup>n</sup></tt>.)
+     *
+     * @param mag magnitude, the most-significant int ({@code mag[0]}) must be non-zero.
+     * @param  n unsigned shift distance, in bits.
+     * @return {@code mag << n}
+     */
     private static int[] shiftLeft(int[] mag, int n) {
         int nInts = n >>> 5;
         int nBits = n & 0x1f;
@@ -2853,21 +2952,31 @@
      *
      * @param  n shift distance, in bits.
      * @return {@code this >> n}
-     * @throws ArithmeticException if the shift distance is {@code
-     *         Integer.MIN_VALUE}.
      * @see #shiftLeft
      */
     public BigInteger shiftRight(int n) {
-        if (n == 0)
+        if (signum == 0)
+            return ZERO;
+        if (n > 0) {
+            return shiftRightImpl(n);
+        } else if (n == 0) {
             return this;
-        if (n < 0) {
-            if (n == Integer.MIN_VALUE) {
-                throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
-            } else {
-                return shiftLeft(-n);
-            }
+        } else {
+            // Possible int overflow in {@code -n} is not a trouble,
+            // because shiftLeft considers its argument unsigned
+            return new BigInteger(shiftLeft(mag, -n), signum);
         }
-
+    }
+
+    /**
+     * Returns a BigInteger whose value is {@code (this >> n)}. The shift
+     * distance, {@code n}, is considered unsigned.
+     * (Computes <tt>floor(this * 2<sup>-n</sup>)</tt>.)
+     *
+     * @param  n unsigned shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    private BigInteger shiftRightImpl(int n) {
         int nInts = n >>> 5;
         int nBits = n & 0x1f;
         int magLen = mag.length;
@@ -3899,7 +4008,7 @@
             ;
 
         int extraByte = (k == byteLength) ? 1 : 0;
-        int intLength = ((byteLength - keep + extraByte) + 3)/4;
+        int intLength = ((byteLength - keep + extraByte) + 3) >>> 2;
         int result[] = new int[intLength];
 
         /* Copy one's complement of input into output, leaving extra
@@ -4135,7 +4244,8 @@
                 message = "BigInteger: Signum not present in stream";
             throw new java.io.StreamCorruptedException(message);
         }
-        if ((magnitude.length == 0) != (sign == 0)) {
+        int[] mag = stripLeadingZeroBytes(magnitude);
+        if ((mag.length == 0) != (sign == 0)) {
             String message = "BigInteger: signum-magnitude mismatch";
             if (fields.defaulted("magnitude"))
                 message = "BigInteger: Magnitude not present in stream";
@@ -4146,7 +4256,14 @@
         UnsafeHolder.putSign(this, sign);
 
         // Calculate mag field from magnitude and discard magnitude
-        UnsafeHolder.putMag(this, stripLeadingZeroBytes(magnitude));
+        UnsafeHolder.putMag(this, mag);
+        if (mag.length >= MAX_MAG_LENGTH) {
+            try {
+                checkRange();
+            } catch (ArithmeticException e) {
+                throw new java.io.StreamCorruptedException("BigInteger: Out of the supported range");
+            }
+        }
     }
 
     // Support for resetting final fields while deserializing
--- a/src/share/classes/java/math/MutableBigInteger.java	Wed Oct 30 17:27:25 2013 -0700
+++ b/src/share/classes/java/math/MutableBigInteger.java	Wed Oct 30 17:45:12 2013 -0700
@@ -1257,14 +1257,14 @@
 
             int j = (s+m-1) / m;      // step 2a: j = ceil(s/m)
             int n = j * m;            // step 2b: block length in 32-bit units
-            int n32 = 32 * n;         // block length in bits
-            int sigma = Math.max(0, n32 - b.bitLength());   // step 3: sigma = max{T | (2^T)*B < beta^n}
+            long n32 = 32L * n;         // block length in bits
+            int sigma = (int) Math.max(0, n32 - b.bitLength());   // step 3: sigma = max{T | (2^T)*B < beta^n}
             MutableBigInteger bShifted = new MutableBigInteger(b);
             bShifted.safeLeftShift(sigma);   // step 4a: shift b so its length is a multiple of n
             safeLeftShift(sigma);     // step 4b: shift this by the same amount
 
             // step 5: t is the number of blocks needed to accommodate this plus one additional bit
-            int t = (bitLength()+n32) / n32;
+            int t = (int) ((bitLength()+n32) / n32);
             if (t < 2) {
                 t = 2;
             }
@@ -1421,10 +1421,10 @@
     }
 
     /** @see BigInteger#bitLength() */
-    int bitLength() {
+    long bitLength() {
         if (intLen == 0)
             return 0;
-        return intLen*32 - Integer.numberOfLeadingZeros(value[offset]);
+        return intLen*32L - Integer.numberOfLeadingZeros(value[offset]);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/math/BigInteger/BitLengthOverflow.java	Wed Oct 30 17:45:12 2013 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @ test
+ * @bug 6910473
+ * @summary Test that bitLength() is not negative
+ * @author Dmitry Nadezhin
+ */
+import java.math.BigInteger;
+
+public class BitLengthOverflow {
+
+    public static void main(String[] args) {
+
+        try {
+            BigInteger x = BigInteger.ONE.shiftLeft(Integer.MAX_VALUE); // x = pow(2,Integer.MAX_VALUE)
+            if (x.bitLength() != (1L << 31))
+                throw new RuntimeException("Incorrect bitLength() " + x.bitLength());
+            System.out.println("Surprisingly passed with correct bitLength() " + x.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+            System.out.println("Overflow is reported by ArithmeticException, as expected");
+        } catch (OutOfMemoryError e) {
+            // possible
+            System.out.println("OutOfMemoryError");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/math/BigInteger/DivisionOverflow.java	Wed Oct 30 17:45:12 2013 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @ test
+ * @bug 8022780
+ * @summary Test division of large values
+ * @author Dmitry Nadezhin
+ */
+import java.math.BigInteger;
+
+public class DivisionOverflow {
+
+    public static void main(String[] args) {
+        try {
+            BigInteger a = BigInteger.ONE.shiftLeft(2147483646);
+            BigInteger b = BigInteger.ONE.shiftLeft(1568);
+            BigInteger[] qr = a.divideAndRemainder(b);
+            BigInteger q = qr[0];
+            BigInteger r = qr[1];
+            if (!r.equals(BigInteger.ZERO))
+                throw new RuntimeException("Incorrect singum() of remainder " + r.signum());
+            if (q.bitLength() != 2147482079)
+                throw new RuntimeException("Incorrect bitLength() of quotient " + q.bitLength());
+            System.out.println("Division of large values passed without overflow.");
+        } catch (OutOfMemoryError e) {
+            // possible
+            System.out.println("OutOfMemoryError");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/math/BigInteger/DoubleValueOverflow.java	Wed Oct 30 17:45:12 2013 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @ test
+ * @bug 8021203
+ * @summary Test that doubleValue() doesn't overflow
+ * @author Dmitry Nadezhin
+ */
+import java.math.BigInteger;
+
+public class DoubleValueOverflow {
+
+    public static void main(String[] args) {
+
+        try {
+            BigInteger x = BigInteger.valueOf(2).shiftLeft(Integer.MAX_VALUE); // x = pow(2,pow(2,31))
+            if (x.doubleValue() != Double.POSITIVE_INFINITY)
+                throw new RuntimeException("Incorrect doubleValue() " + x.doubleValue());
+            System.out.println("Passed with correct result");
+        } catch (ArithmeticException e) {
+            // expected
+            System.out.println("Overflow is reported by ArithmeticException, as expected");
+        } catch (OutOfMemoryError e) {
+            // possible
+            System.out.println("OutOfMemoryError");
+        }
+    }
+}
--- a/test/java/math/BigInteger/ExtremeShiftingTests.java	Wed Oct 30 17:27:25 2013 -0700
+++ b/test/java/math/BigInteger/ExtremeShiftingTests.java	Wed Oct 30 17:45:12 2013 -0700
@@ -27,22 +27,41 @@
  * @summary Tests of shiftLeft and shiftRight on Integer.MIN_VALUE
  * @author Joseph D. Darcy
  */
+import java.math.BigInteger;
 import static java.math.BigInteger.*;
 
 public class ExtremeShiftingTests {
     public static void main(String... args) {
+        BigInteger bi = ONE.shiftLeft(Integer.MIN_VALUE);
+        if (!bi.equals(ZERO))
+            throw new RuntimeException("1 << " + Integer.MIN_VALUE);
+
+        bi = ZERO.shiftLeft(Integer.MIN_VALUE);
+        if (!bi.equals(ZERO))
+            throw new RuntimeException("0 << " + Integer.MIN_VALUE);
+
+        bi = BigInteger.valueOf(-1);
+        bi = bi.shiftLeft(Integer.MIN_VALUE);
+        if (!bi.equals(BigInteger.valueOf(-1)))
+            throw new RuntimeException("-1 << " + Integer.MIN_VALUE);
+
         try {
-            ONE.shiftLeft(Integer.MIN_VALUE);
-            throw new RuntimeException("Should not reach here.");
+            ONE.shiftRight(Integer.MIN_VALUE);
+            throw new RuntimeException("1 >> " + Integer.MIN_VALUE);
         } catch (ArithmeticException ae) {
             ; // Expected
         }
 
+        bi = ZERO.shiftRight(Integer.MIN_VALUE);
+        if (!bi.equals(ZERO))
+            throw new RuntimeException("0 >> " + Integer.MIN_VALUE);
+
         try {
-            ONE.shiftRight(Integer.MIN_VALUE);
-            throw new RuntimeException("Should not reach here.");
+            BigInteger.valueOf(-1).shiftRight(Integer.MIN_VALUE);
+            throw new RuntimeException("-1 >> " + Integer.MIN_VALUE);
         } catch (ArithmeticException ae) {
             ; // Expected
         }
+
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/math/BigInteger/StringConstructorOverflow.java	Wed Oct 30 17:45:12 2013 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @ test
+ * @bug 8021204
+ * @summary Test constructor BigInteger(String val, int radix) on very long string
+ * @author Dmitry Nadezhin
+ */
+import java.math.BigInteger;
+
+public class StringConstructorOverflow {
+
+    // String with hexadecimal value pow(2,pow(2,34))+1
+    private static String makeLongHexString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append('1');
+        for (int i = 0; i < (1 << 30) - 1; i++) {
+            sb.append('0');
+        }
+        sb.append('1');
+        return sb.toString();
+    }
+
+    public static void main(String[] args) {
+        try {
+            BigInteger bi = new BigInteger(makeLongHexString(), 16);
+            if (bi.compareTo(BigInteger.ONE) <= 0)
+                throw new RuntimeException("Incorrect result " + bi.toString());
+        } catch (ArithmeticException e) {
+            // expected
+            System.out.println("Overflow is reported by ArithmeticException, as expected");
+        } catch (OutOfMemoryError e) {
+            // possible
+            System.out.println("OutOfMemoryError");
+            System.out.println("Run jtreg with -javaoption:-Xmx8g");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/math/BigInteger/SymmetricRangeTests.java	Wed Oct 30 17:45:12 2013 -0700
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This test is intentionally ignored because of huge memory requirements
+ * @ test
+ * @run main/timeout=180/othervm -Xmx8g SymmetricRangeTests
+ * @bug 6910473 8021204 8021203 9005933
+ * @summary Test range of BigInteger values
+ * @author Dmitry Nadezhin
+ */
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Random;
+import java.math.BigInteger;
+
+public class SymmetricRangeTests {
+
+    private static final BigInteger MAX_VALUE = makeMaxValue();
+    private static final BigInteger MIN_VALUE = MAX_VALUE.negate();
+
+    private static BigInteger makeMaxValue() {
+        byte[] ba = new byte[1 << 28];
+        Arrays.fill(ba, (byte) 0xFF);
+        ba[0] = (byte) 0x7F;
+        return new BigInteger(ba);
+    }
+
+    private static void check(String msg, BigInteger actual, BigInteger expected) {
+        if (!actual.equals(expected)) {
+            throw new RuntimeException(msg + ".bitLength()=" + actual.bitLength());
+        }
+    }
+
+    private static void check(String msg, double actual, double expected) {
+        if (actual != expected) {
+            throw new RuntimeException(msg + "=" + actual);
+        }
+    }
+
+    private static void check(String msg, float actual, float expected) {
+        if (actual != expected) {
+            throw new RuntimeException(msg + "=" + actual);
+        }
+    }
+
+    private static void check(String msg, long actual, long expected) {
+        if (actual != expected) {
+            throw new RuntimeException(msg + "=" + actual);
+        }
+    }
+
+    private static void check(String msg, int actual, int expected) {
+        if (actual != expected) {
+            throw new RuntimeException(msg + "=" + actual);
+        }
+    }
+
+    private static void testOverflowInMakePositive() {
+        System.out.println("Testing overflow in BigInteger.makePositive");
+        byte[] ba = new byte[Integer.MAX_VALUE - 2];
+        ba[0] = (byte) 0x80;
+        try {
+            BigInteger actual = new BigInteger(ba);
+            throw new RuntimeException("new BigInteger(ba).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testBug8021204() {
+        System.out.println("Testing Bug 8021204");
+        StringBuilder sb = new StringBuilder();
+        sb.append('1');
+        for (int i = 0; i < (1 << 30) - 1; i++) {
+            sb.append('0');
+        }
+        sb.append('1');
+        String s = sb.toString();
+        sb = null;
+        try {
+            BigInteger actual = new BigInteger(s, 16);
+            throw new RuntimeException("new BigInteger(\"1000...001\").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testOverflowInBitSieve() {
+        System.out.println("Testing overflow in BitSieve.sieveSingle");
+        int bitLength = (5 << 27) - 1;
+        try {
+            Random rnd = new Random();
+            BigInteger actual = new BigInteger(bitLength, 0, rnd);
+            throw new RuntimeException("new BigInteger(bitLength, 0, null).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger bi = BigInteger.ONE.shiftLeft(bitLength - 1).subtract(BigInteger.ONE);
+            BigInteger actual = bi.nextProbablePrime();
+            throw new RuntimeException("bi.nextActualPrime().bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testAdd() {
+        System.out.println("Testing BigInteger.add");
+        try {
+            BigInteger actual = MAX_VALUE.add(BigInteger.ONE);
+            throw new RuntimeException("BigInteger.MAX_VALUE.add(BigInteger.ONE).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testSubtract() {
+        System.out.println("Testing BigInteger.subtract");
+        try {
+            BigInteger actual = MIN_VALUE.subtract(BigInteger.ONE);
+            throw new RuntimeException("BigInteger.MIN_VALUE.subtract(BigInteger.ONE).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testMultiply() {
+        System.out.println("Testing BigInteger.multiply");
+        int py = 2000;
+        int px = Integer.MAX_VALUE - py;
+        BigInteger x = BigInteger.ONE.shiftLeft(px);
+        BigInteger y = BigInteger.ONE.shiftLeft(py);
+        try {
+            BigInteger actual = x.multiply(y);
+            throw new RuntimeException("(1 << " + px + " ) * (1 << " + py + ").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testDivide() {
+        System.out.println("Testing BigInteger.divide");
+        check("BigInteger.MIN_VALUE.divide(BigInteger.valueOf(-1))",
+                MIN_VALUE.divide(BigInteger.valueOf(-1)), MAX_VALUE);
+        check("BigInteger.MIN_VALUE.divide(BigInteger.ONE)",
+                MIN_VALUE.divide(BigInteger.ONE), MIN_VALUE);
+    }
+
+    private static void testDivideAndRemainder(String msg, BigInteger dividend, BigInteger divisor,
+            BigInteger expectedQuotent, BigInteger expectedRemainder) {
+        BigInteger[] qr = dividend.divideAndRemainder(divisor);
+        check(msg + "[0]", qr[0], expectedQuotent);
+        check(msg + "[1]", qr[1], expectedRemainder);
+    }
+
+    private static void testDivideAndRemainder() {
+        System.out.println("Testing BigInteger.divideAndRemainder");
+        testDivideAndRemainder("BigInteger.MIN_VALUE.divideAndRemainder(BigInteger.valueOf(-1))",
+                MIN_VALUE, BigInteger.valueOf(-1),
+                MAX_VALUE,
+                BigInteger.ZERO);
+    }
+
+    private static void testBug9005933() {
+        System.out.println("Testing Bug 9005933");
+        int dividendPow = 2147483646;
+        int divisorPow = 1568;
+        BigInteger dividend = BigInteger.ONE.shiftLeft(dividendPow);
+        BigInteger divisor = BigInteger.ONE.shiftLeft(divisorPow);
+        testDivideAndRemainder("(1 << " + dividendPow + ").divideAndRemainder(1 << " + divisorPow + ")",
+                dividend, divisor,
+                BigInteger.ONE.shiftLeft(dividendPow - divisorPow),
+                BigInteger.ZERO);
+    }
+
+    private static void testRemainder() {
+        System.out.println("Testing BigInteger.remainder");
+        check("BigInteger.MIN_VALUE.remainder(BigInteger.valueOf(-1))",
+                MIN_VALUE.remainder(BigInteger.valueOf(-1)), BigInteger.ZERO);
+    }
+
+    private static void testPow() {
+        System.out.println("Testing BigInteger.pow");
+        check("BigInteger.MIN_VALUE.pow(1)",
+                MIN_VALUE.pow(1), MIN_VALUE);
+        try {
+            BigInteger actual = BigInteger.valueOf(4).pow(Integer.MAX_VALUE);
+            throw new RuntimeException("BigInteger.valueOf(4).pow(Integer.MAX_VALUE).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testGcd() {
+        System.out.println("Testing BigInteger.gcd");
+        check("BigInteger.MIN_VALUE.gcd(BigInteger.MIN_VALUE)",
+                MIN_VALUE.gcd(MIN_VALUE), MAX_VALUE);
+        check("BigInteger.MIN_VALUE.gcd(BigInteger.ZERO)",
+                MIN_VALUE.gcd(BigInteger.ZERO), MAX_VALUE);
+        check("BigInteger.ZERO.gcd(MIN_VALUE)",
+                BigInteger.ZERO.gcd(MIN_VALUE), MAX_VALUE);
+    }
+
+    private static void testAbs() {
+        System.out.println("Testing BigInteger.abs");
+        check("BigInteger.MIN_VALUE.abs()",
+                MIN_VALUE.abs(), MAX_VALUE);
+        check("BigInteger.MAX_VALUE.abs()",
+                MAX_VALUE.abs(), MAX_VALUE);
+    }
+
+    private static void testNegate() {
+        System.out.println("Testing BigInteger.negate");
+        check("BigInteger.MIN_VALUE.negate()",
+                MIN_VALUE.negate(), MAX_VALUE);
+        check("BigInteger.MAX_VALUE.negate()",
+                MAX_VALUE.negate(), MIN_VALUE);
+    }
+
+    private static void testMod() {
+        System.out.println("Testing BigInteger.mod");
+        check("BigInteger.MIN_VALUE.mod(BigInteger.MAX_VALUE)",
+                MIN_VALUE.mod(MAX_VALUE), BigInteger.ZERO);
+        check("BigInteger.MAX_VALUE.mod(BigInteger.MAX_VALUE)",
+                MIN_VALUE.mod(MAX_VALUE), BigInteger.ZERO);
+    }
+
+    private static void testModPow() {
+        System.out.println("Testing BigInteger.modPow");
+        BigInteger x = BigInteger.valueOf(3);
+        BigInteger m = BigInteger.valueOf(-4).subtract(MIN_VALUE);
+        check("BigInteger.valueOf(3).modPow(BigInteger.ONE, m)",
+                x.modPow(BigInteger.ONE, m), x);
+    }
+
+    // slow test
+    private static void testModInverse() {
+        System.out.println("Testing BigInteger.modInverse");
+        check("BigInteger.MIN_VALUE.modInverse(BigInteger.MAX_VALUE)",
+                MIN_VALUE.modInverse(MAX_VALUE), MAX_VALUE.subtract(BigInteger.ONE));
+    }
+
+    private static void testShiftLeft() {
+        System.out.println("Testing BigInteger.shiftLeft");
+        try {
+            BigInteger actual = MIN_VALUE.shiftLeft(1);
+            throw new RuntimeException("BigInteger.MIN_VALUE.shiftLeft(1).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = MAX_VALUE.shiftLeft(1);
+            throw new RuntimeException("BigInteger.MAX_VALUE.shiftLeft(1).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testShiftRight() {
+        System.out.println("Testing BigInteger.shiftRight");
+        try {
+            BigInteger actual = MIN_VALUE.shiftRight(-1);
+            throw new RuntimeException("BigInteger.MIN_VALUE.shiftRight(-1).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = MAX_VALUE.shiftRight(-1);
+            throw new RuntimeException("BigInteger.MAX_VALUE.shiftRight(-1).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testAnd() {
+        System.out.println("Testing BigInteger.and");
+        check("BigInteger.MIN_VALUE.and(BigInteger.MIN_VALUE)",
+                MIN_VALUE.and(MIN_VALUE), MIN_VALUE);
+        check("BigInteger.MAX_VALUE.and(BigInteger.MAX_VALUE)",
+                MAX_VALUE.and(MAX_VALUE), MAX_VALUE);
+        check("BigInteger.MIN_VALUE.and(BigInteger.MAX_VALUE)",
+                MIN_VALUE.and(MAX_VALUE), BigInteger.ONE);
+        try {
+            BigInteger actual = MIN_VALUE.and(BigInteger.valueOf(-2));
+            throw new RuntimeException("BigInteger.MIN_VALUE.and(-2)).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testOr() {
+        System.out.println("Testing BigInteger.or");
+        check("BigInteger.MIN_VALUE.or(BigInteger.MIN_VALUE)",
+                MIN_VALUE.or(MIN_VALUE), MIN_VALUE);
+        check("BigInteger.MAX_VALUE.or(BigInteger.MAX_VALUE)",
+                MAX_VALUE.or(MAX_VALUE), MAX_VALUE);
+        check("BigInteger.MIN_VALUE.and(BigInteger.MAX_VALUE)",
+                MIN_VALUE.or(MAX_VALUE), BigInteger.valueOf(-1));
+    }
+
+    private static void testXor() {
+        System.out.println("Testing BigInteger.xor");
+        check("BigInteger.MIN_VALUE.xor(BigInteger.MIN_VALUE)",
+                MIN_VALUE.xor(MIN_VALUE), BigInteger.ZERO);
+        check("BigInteger.MAX_VALUE.xor(BigInteger.MAX_VALUE)",
+                MAX_VALUE.xor(MAX_VALUE), BigInteger.ZERO);
+        check("BigInteger.MIN_VALUE.xor(BigInteger.MAX_VALUE)",
+                MIN_VALUE.xor(MAX_VALUE), BigInteger.valueOf(-2));
+        try {
+            BigInteger actual = MIN_VALUE.xor(BigInteger.ONE);
+            throw new RuntimeException("BigInteger.MIN_VALUE.xor(BigInteger.ONE)).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testNot() {
+        System.out.println("Testing BigInteger.not");
+        check("BigInteger.MIN_VALUE.not()",
+                MIN_VALUE.not(), MAX_VALUE.subtract(BigInteger.ONE));
+        try {
+            BigInteger actual = MAX_VALUE.not();
+            throw new RuntimeException("BigInteger.MAX_VALUE.not()).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testSetBit() {
+        System.out.println("Testing BigInteger.setBit");
+        check("BigInteger.MIN_VALUE.setBit(" + Integer.MAX_VALUE + ")",
+                MIN_VALUE.setBit(Integer.MAX_VALUE), MIN_VALUE);
+        try {
+            BigInteger actual = MAX_VALUE.setBit(Integer.MAX_VALUE);
+            throw new RuntimeException("BigInteger.MAX_VALUE.setBit(" + Integer.MAX_VALUE + ").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testClearBit() {
+        System.out.println("Testing BigInteger.clearBit");
+        check("BigInteger.MAX_VALUE.clearBit(" + Integer.MAX_VALUE + ")",
+                MAX_VALUE.clearBit(Integer.MAX_VALUE), MAX_VALUE);
+        try {
+            BigInteger actual = MIN_VALUE.clearBit(Integer.MAX_VALUE);
+            throw new RuntimeException("BigInteger.MIN_VALUE.clearBit(" + Integer.MAX_VALUE + ").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = MIN_VALUE.clearBit(0);
+            throw new RuntimeException("BigInteger.MIN_VALUE.clearBit(0).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testFlipBit() {
+        System.out.println("Testing BigInteger.flipBit");
+        try {
+            BigInteger actual = MIN_VALUE.flipBit(Integer.MAX_VALUE);
+            throw new RuntimeException("BigInteger.MIN_VALUE.flipBit(" + Integer.MAX_VALUE + ").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = MIN_VALUE.flipBit(0);
+            throw new RuntimeException("BigInteger.MIN_VALUE.flipBit(0).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = MAX_VALUE.flipBit(Integer.MAX_VALUE);
+            throw new RuntimeException("BigInteger.MAX_VALUE.flipBit(" + Integer.MAX_VALUE + ").bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testGetLowestSetBit() {
+        System.out.println("Testing BigInteger.getLowestSetBit");
+        check("BigInteger.MIN_VALUE.getLowestSetBit()",
+                MIN_VALUE.getLowestSetBit(), 0);
+        check("BigInteger.MAX_VALUE.getLowestSetBit()",
+                MAX_VALUE.getLowestSetBit(), 0);
+    }
+
+    private static void testBitLength() {
+        System.out.println("Testing BigInteger.bitLength");
+        check("BigInteger.MIN_NEXT.bitLength()",
+                MIN_VALUE.bitLength(), Integer.MAX_VALUE);
+        check("BigInteger.MAX_VALUE.bitLength()",
+                MAX_VALUE.bitLength(), Integer.MAX_VALUE);
+    }
+
+    private static void testBitCount() {
+        System.out.println("Testing BigInteger.bitCount");
+        check("BigInteger.MIN_VALUE.bitCount()",
+                MIN_VALUE.bitCount(), Integer.MAX_VALUE - 1);
+        check("BigInteger.MAX_VALUE.bitCount()",
+                MAX_VALUE.bitCount(), Integer.MAX_VALUE);
+    }
+
+    private static void testToString(String msg, int radix, BigInteger bi, int length, String startsWith, char c) {
+        String s = bi.toString(radix);
+        if (s.length() != length) {
+            throw new RuntimeException(msg + ".length=" + s.length());
+        }
+        if (!s.startsWith(startsWith)) {
+            throw new RuntimeException(msg + "[0]=" + s.substring(0, startsWith.length()));
+        }
+        for (int i = startsWith.length(); i < s.length(); i++) {
+            if (s.charAt(i) != c) {
+                throw new RuntimeException(msg + "[" + i + "]='" + s.charAt(i) + "'");
+            }
+        }
+    }
+
+    private static void testToString() {
+        System.out.println("Testing BigInteger.toString");
+        testToString("BigInteger.MIN_VALUE.toString(16)=", 16,
+                BigInteger.valueOf(-1).shiftLeft(Integer.MAX_VALUE - 1),
+                (1 << 29) + 1, "-4", '0');
+    }
+
+    private static void testToByteArrayWithConstructor(String msg, BigInteger bi, int length, byte msb, byte b, byte lsb) {
+        byte[] ba = bi.toByteArray();
+        if (ba.length != length) {
+            throw new RuntimeException(msg + ".length=" + ba.length);
+        }
+        if (ba[0] != msb) {
+            throw new RuntimeException(msg + "[0]=" + ba[0]);
+        }
+        for (int i = 1; i < ba.length - 1; i++) {
+            if (ba[i] != b) {
+                throw new RuntimeException(msg + "[" + i + "]=" + ba[i]);
+            }
+        }
+        if (ba[ba.length - 1] != lsb) {
+            throw new RuntimeException(msg + "[" + (ba.length - 1) + "]=" + ba[ba.length - 1]);
+        }
+        BigInteger actual = new BigInteger(ba);
+        if (!actual.equals(bi)) {
+            throw new RuntimeException(msg + ".bitLength()=" + actual.bitLength());
+        }
+    }
+
+    private static void testToByteArrayWithConstructor() {
+        System.out.println("Testing BigInteger.toByteArray with constructor");
+        testToByteArrayWithConstructor("BigInteger.MIN_VALUE.toByteArray()",
+                MIN_VALUE, (1 << 28), (byte) 0x80, (byte) 0x00, (byte) 0x01);
+        testToByteArrayWithConstructor("BigInteger.MAX_VALUE.toByteArray()",
+                MAX_VALUE, (1 << 28), (byte) 0x7f, (byte) 0xff, (byte) 0xff);
+
+        byte[] ba = new byte[1 << 28];
+        ba[0] = (byte) 0x80;
+        try {
+            BigInteger actual = new BigInteger(-1, ba);
+            throw new RuntimeException("new BigInteger(-1, ba).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        try {
+            BigInteger actual = new BigInteger(1, ba);
+            throw new RuntimeException("new BigInteger(1, ba).bitLength()=" + actual.bitLength());
+        } catch (ArithmeticException e) {
+            // expected
+        }
+    }
+
+    private static void testIntValue() {
+        System.out.println("Testing BigInteger.intValue");
+        check("BigInteger.MIN_VALUE.intValue()",
+                MIN_VALUE.intValue(), 1);
+        check("BigInteger.MAX_VALUE.floatValue()",
+                MAX_VALUE.intValue(), -1);
+    }
+
+    private static void testLongValue() {
+        System.out.println("Testing BigInteger.longValue");
+        check("BigInteger.MIN_VALUE.longValue()",
+                MIN_VALUE.longValue(), 1L);
+        check("BigInteger.MAX_VALUE.longValue()",
+                MAX_VALUE.longValue(), -1L);
+    }
+
+    private static void testFloatValue() {
+        System.out.println("Testing BigInteger.floatValue, Bug 8021203");
+        check("BigInteger.MIN_VALUE_.floatValue()",
+                MIN_VALUE.floatValue(), Float.NEGATIVE_INFINITY);
+        check("BigInteger.MAX_VALUE.floatValue()",
+                MAX_VALUE.floatValue(), Float.POSITIVE_INFINITY);
+    }
+
+    private static void testDoubleValue() {
+        System.out.println("Testing BigInteger.doubleValue, Bug 8021203");
+        check("BigInteger.MIN_VALUE.doubleValue()",
+                MIN_VALUE.doubleValue(), Double.NEGATIVE_INFINITY);
+        check("BigInteger.MAX_VALUE.doubleValue()",
+                MAX_VALUE.doubleValue(), Double.POSITIVE_INFINITY);
+    }
+
+    private static void testSerialization(String msg, BigInteger bi) {
+        try {
+            ByteArrayOutputStream baOut = new ByteArrayOutputStream((1 << 28) + 1000);
+            ObjectOutputStream out = new ObjectOutputStream(baOut);
+            out.writeObject(bi);
+            out.close();
+            out = null;
+            byte[] ba = baOut.toByteArray();
+            baOut = null;
+            ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(ba));
+            BigInteger actual = (BigInteger) in.readObject();
+            if (!actual.equals(bi)) {
+                throw new RuntimeException(msg + ".bitLength()=" + actual.bitLength());
+            }
+        } catch (IOException | ClassNotFoundException e) {
+            throw new RuntimeException(msg + " raised exception ", e);
+        }
+    }
+
+    private static void testSerialization() {
+        System.out.println("Testing BigInteger serialization");
+        testSerialization("BigInteger.MIN_VALUE.intValue()",
+                MIN_VALUE);
+        testSerialization("BigInteger.MAX_VALUE.floatValue()",
+                MAX_VALUE);
+    }
+
+    private static void testLongValueExact() {
+        System.out.println("Testing BigInteger.longValueExact");
+        try {
+            long actual = MIN_VALUE.longValueExact();
+            throw new RuntimeException("BigInteger.MIN_VALUE.longValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+        try {
+            long actual = MAX_VALUE.longValueExact();
+            throw new RuntimeException("BigInteger.MAX_VALUE.longValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+    }
+
+    private static void testIntValueExact() {
+        System.out.println("Testing BigInteger.intValueExact");
+        try {
+            long actual = MIN_VALUE.intValueExact();
+            throw new RuntimeException("BigInteger.MIN_VALUE.intValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+        try {
+            long actual = MAX_VALUE.intValueExact();
+            throw new RuntimeException("BigInteger.MAX_VALUE.intValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+    }
+
+    private static void testShortValueExact() {
+        System.out.println("Testing BigInteger.shortValueExact");
+        try {
+            long actual = MIN_VALUE.shortValueExact();
+            throw new RuntimeException("BigInteger.MIN_VALUE.shortValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+        try {
+            long actual = MAX_VALUE.shortValueExact();
+            throw new RuntimeException("BigInteger.MAX_VALUE.shortValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+    }
+
+    private static void testByteValueExact() {
+        System.out.println("Testing BigInteger.byteValueExact");
+        try {
+            long actual = MIN_VALUE.byteValueExact();
+            throw new RuntimeException("BigInteger.MIN_VALUE.byteValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+        try {
+            long actual = MAX_VALUE.byteValueExact();
+            throw new RuntimeException("BigInteger.MAX_VALUE.byteValueExact()= " + actual);
+        } catch (ArithmeticException e) {
+            // excpected
+        }
+    }
+
+    public static void main(String... args) {
+        testOverflowInMakePositive();
+        testBug8021204();
+        testOverflowInBitSieve();
+        testAdd();
+        testSubtract();
+        testMultiply();
+        testDivide();
+        testDivideAndRemainder();
+        testBug9005933();
+        testRemainder();
+        testPow();
+        testGcd();
+        testAbs();
+        testNegate();
+        testMod();
+        testModPow();
+//        testModInverse();
+        testShiftLeft();
+        testShiftRight();
+        testAnd();
+        testOr();
+        testXor();
+        testNot();
+        testSetBit();
+        testClearBit();
+        testFlipBit();
+        testGetLowestSetBit();
+        testBitLength();
+        testBitCount();
+        testToString();
+        testToByteArrayWithConstructor();
+        testIntValue();
+        testLongValue();
+        testFloatValue();
+        testDoubleValue();
+        testSerialization();
+        testLongValueExact();
+        testIntValueExact();
+        testShortValueExact();
+        testByteValueExact();
+    }
+}