src/share/classes/java/lang/Long.java

Print this page
rev 8975 : 8030814: Long.parseUnsignedLong should throwexception on too large input
Summary: Change test for overflow of unsigned long
Reviewed-by: TBD

@@ -63,10 +63,16 @@
      * have, 2<sup>63</sup>-1.
      */
     @Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
 
     /**
+     * A constant holding the maximum value a 64-bit unsigned long could
+     * have, 2<sup>64</sup>-1.
+     */
+    private static long MAX_UNSIGNED = 0xffffffffffffffffL;
+
+    /**
      * The {@code Class} instance representing the primitive type
      * {@code long}.
      *
      * @since   JDK1.1
      */

@@ -629,10 +635,25 @@
      */
     public static long parseLong(String s) throws NumberFormatException {
         return parseLong(s, 10);
     }
 
+    private static class ParseUnsignedCache {
+        private ParseUnsignedCache(){}
+
+        static final long[] div = new long[Character.MAX_RADIX];
+        static final long[] rem = new long[Character.MAX_RADIX];
+
+        static {
+            // div[0] and rem[0] are unused.
+            for(int radix = 1; radix < Character.MAX_RADIX; radix++) {
+                div[radix] = divideUnsigned(MAX_UNSIGNED, radix);
+                rem[radix] = remainderUnsigned(MAX_UNSIGNED, radix);
+            }
+        }
+    }
+
     /**
      * Parses the string argument as an unsigned {@code long} in the
      * radix specified by the second argument.  An unsigned integer
      * maps the values usually associated with negative numbers to
      * positive numbers larger than {@code MAX_VALUE}.

@@ -697,12 +718,13 @@
                 long first = parseLong(s.substring(0, len - 1), radix);
                 int second = Character.digit(s.charAt(len - 1), radix);
                 if (second < 0) {
                     throw new NumberFormatException("Bad digit at end of " + s);
                 }
-                long result = first * radix + second;
-                if (compareUnsigned(result, first) < 0) {
+                if (compareUnsigned(first, ParseUnsignedCache.div[radix]) > 0 ||
+                        (first == ParseUnsignedCache.div[radix] &&
+                        second > ParseUnsignedCache.rem[radix])) {
                     /*
                      * The maximum unsigned value, (2^64)-1, takes at
                      * most one more digit to represent than the
                      * maximum signed value, (2^63)-1.  Therefore,
                      * parsing (len - 1) digits will be appropriately

@@ -717,11 +739,11 @@
                      * digit.
                      */
                     throw new NumberFormatException(String.format("String value %s exceeds " +
                                                                   "range of unsigned long.", s));
                 }
-                return result;
+                return first * radix + second;
             }
         } else {
             throw NumberFormatException.forInputString(s);
         }
     }