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


  48  * @author  Lee Boynton
  49  * @author  Arthur van Hoff
  50  * @author  Josh Bloch
  51  * @author  Joseph D. Darcy
  52  * @since   JDK1.0
  53  */
  54 public final class Long extends Number implements Comparable<Long> {
  55     /**
  56      * A constant holding the minimum value a {@code long} can
  57      * have, -2<sup>63</sup>.
  58      */
  59     @Native public static final long MIN_VALUE = 0x8000000000000000L;
  60 
  61     /**
  62      * A constant holding the maximum value a {@code long} can
  63      * have, 2<sup>63</sup>-1.
  64      */
  65     @Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
  66 
  67     /**






  68      * The {@code Class} instance representing the primitive type
  69      * {@code long}.
  70      *
  71      * @since   JDK1.1
  72      */
  73     @SuppressWarnings("unchecked")
  74     public static final Class<Long>     TYPE = (Class<Long>) Class.getPrimitiveClass("long");
  75 
  76     /**
  77      * Returns a string representation of the first argument in the
  78      * radix specified by the second argument.
  79      *
  80      * <p>If the radix is smaller than {@code Character.MIN_RADIX}
  81      * or larger than {@code Character.MAX_RADIX}, then the radix
  82      * {@code 10} is used instead.
  83      *
  84      * <p>If the first argument is negative, the first element of the
  85      * result is the ASCII minus sign {@code '-'}
  86      * ({@code '\u005Cu002d'}). If the first argument is not
  87      * negative, no sign character appears in the result.


 614      * were given as arguments to the {@link
 615      * #parseLong(java.lang.String, int)} method.
 616      *
 617      * <p>Note that neither the character {@code L}
 618      * ({@code '\u005Cu004C'}) nor {@code l}
 619      * ({@code '\u005Cu006C'}) is permitted to appear at the end
 620      * of the string as a type indicator, as would be permitted in
 621      * Java programming language source code.
 622      *
 623      * @param      s   a {@code String} containing the {@code long}
 624      *             representation to be parsed
 625      * @return     the {@code long} represented by the argument in
 626      *             decimal.
 627      * @throws     NumberFormatException  if the string does not contain a
 628      *             parsable {@code long}.
 629      */
 630     public static long parseLong(String s) throws NumberFormatException {
 631         return parseLong(s, 10);
 632     }
 633 















 634     /**
 635      * Parses the string argument as an unsigned {@code long} in the
 636      * radix specified by the second argument.  An unsigned integer
 637      * maps the values usually associated with negative numbers to
 638      * positive numbers larger than {@code MAX_VALUE}.
 639      *
 640      * The characters in the string must all be digits of the
 641      * specified radix (as determined by whether {@link
 642      * java.lang.Character#digit(char, int)} returns a nonnegative
 643      * value), except that the first character may be an ASCII plus
 644      * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
 645      * integer value is returned.
 646      *
 647      * <p>An exception of type {@code NumberFormatException} is
 648      * thrown if any of the following situations occurs:
 649      * <ul>
 650      * <li>The first argument is {@code null} or is a string of
 651      * length zero.
 652      *
 653      * <li>The radix is either smaller than


 682 
 683         int len = s.length();
 684         if (len > 0) {
 685             char firstChar = s.charAt(0);
 686             if (firstChar == '-') {
 687                 throw new
 688                     NumberFormatException(String.format("Illegal leading minus sign " +
 689                                                        "on unsigned string %s.", s));
 690             } else {
 691                 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
 692                     (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
 693                     return parseLong(s, radix);
 694                 }
 695 
 696                 // No need for range checks on len due to testing above.
 697                 long first = parseLong(s.substring(0, len - 1), radix);
 698                 int second = Character.digit(s.charAt(len - 1), radix);
 699                 if (second < 0) {
 700                     throw new NumberFormatException("Bad digit at end of " + s);
 701                 }
 702                 long result = first * radix + second;
 703                 if (compareUnsigned(result, first) < 0) {

 704                     /*
 705                      * The maximum unsigned value, (2^64)-1, takes at
 706                      * most one more digit to represent than the
 707                      * maximum signed value, (2^63)-1.  Therefore,
 708                      * parsing (len - 1) digits will be appropriately
 709                      * in-range of the signed parsing.  In other
 710                      * words, if parsing (len -1) digits overflows
 711                      * signed parsing, parsing len digits will
 712                      * certainly overflow unsigned parsing.
 713                      *
 714                      * The compareUnsigned check above catches
 715                      * situations where an unsigned overflow occurs
 716                      * incorporating the contribution of the final
 717                      * digit.
 718                      */
 719                     throw new NumberFormatException(String.format("String value %s exceeds " +
 720                                                                   "range of unsigned long.", s));
 721                 }
 722                 return result;
 723             }
 724         } else {
 725             throw NumberFormatException.forInputString(s);
 726         }
 727     }
 728 
 729     /**
 730      * Parses the string argument as an unsigned decimal {@code long}. The
 731      * characters in the string must all be decimal digits, except
 732      * that the first character may be an an ASCII plus sign {@code
 733      * '+'} ({@code '\u005Cu002B'}). The resulting integer value
 734      * is returned, exactly as if the argument and the radix 10 were
 735      * given as arguments to the {@link
 736      * #parseUnsignedLong(java.lang.String, int)} method.
 737      *
 738      * @param s   a {@code String} containing the unsigned {@code long}
 739      *            representation to be parsed
 740      * @return    the unsigned {@code long} value represented by the decimal string argument
 741      * @throws    NumberFormatException  if the string does not contain a
 742      *            parsable unsigned integer.




  48  * @author  Lee Boynton
  49  * @author  Arthur van Hoff
  50  * @author  Josh Bloch
  51  * @author  Joseph D. Darcy
  52  * @since   JDK1.0
  53  */
  54 public final class Long extends Number implements Comparable<Long> {
  55     /**
  56      * A constant holding the minimum value a {@code long} can
  57      * have, -2<sup>63</sup>.
  58      */
  59     @Native public static final long MIN_VALUE = 0x8000000000000000L;
  60 
  61     /**
  62      * A constant holding the maximum value a {@code long} can
  63      * have, 2<sup>63</sup>-1.
  64      */
  65     @Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
  66 
  67     /**
  68      * A constant holding the maximum value a 64-bit unsigned long could
  69      * have, 2<sup>64</sup>-1.
  70      */
  71     private static long MAX_UNSIGNED = 0xffffffffffffffffL;
  72 
  73     /**
  74      * The {@code Class} instance representing the primitive type
  75      * {@code long}.
  76      *
  77      * @since   JDK1.1
  78      */
  79     @SuppressWarnings("unchecked")
  80     public static final Class<Long>     TYPE = (Class<Long>) Class.getPrimitiveClass("long");
  81 
  82     /**
  83      * Returns a string representation of the first argument in the
  84      * radix specified by the second argument.
  85      *
  86      * <p>If the radix is smaller than {@code Character.MIN_RADIX}
  87      * or larger than {@code Character.MAX_RADIX}, then the radix
  88      * {@code 10} is used instead.
  89      *
  90      * <p>If the first argument is negative, the first element of the
  91      * result is the ASCII minus sign {@code '-'}
  92      * ({@code '\u005Cu002d'}). If the first argument is not
  93      * negative, no sign character appears in the result.


 620      * were given as arguments to the {@link
 621      * #parseLong(java.lang.String, int)} method.
 622      *
 623      * <p>Note that neither the character {@code L}
 624      * ({@code '\u005Cu004C'}) nor {@code l}
 625      * ({@code '\u005Cu006C'}) is permitted to appear at the end
 626      * of the string as a type indicator, as would be permitted in
 627      * Java programming language source code.
 628      *
 629      * @param      s   a {@code String} containing the {@code long}
 630      *             representation to be parsed
 631      * @return     the {@code long} represented by the argument in
 632      *             decimal.
 633      * @throws     NumberFormatException  if the string does not contain a
 634      *             parsable {@code long}.
 635      */
 636     public static long parseLong(String s) throws NumberFormatException {
 637         return parseLong(s, 10);
 638     }
 639 
 640     private static class ParseUnsignedCache {
 641         private ParseUnsignedCache(){}
 642 
 643         static final long[] div = new long[Character.MAX_RADIX];
 644         static final long[] rem = new long[Character.MAX_RADIX];
 645 
 646         static {
 647             // div[0] and rem[0] are unused.
 648             for(int radix = 1; radix < Character.MAX_RADIX; radix++) {
 649                 div[radix] = divideUnsigned(MAX_UNSIGNED, radix);
 650                 rem[radix] = remainderUnsigned(MAX_UNSIGNED, radix);
 651             }
 652         }
 653     }
 654 
 655     /**
 656      * Parses the string argument as an unsigned {@code long} in the
 657      * radix specified by the second argument.  An unsigned integer
 658      * maps the values usually associated with negative numbers to
 659      * positive numbers larger than {@code MAX_VALUE}.
 660      *
 661      * The characters in the string must all be digits of the
 662      * specified radix (as determined by whether {@link
 663      * java.lang.Character#digit(char, int)} returns a nonnegative
 664      * value), except that the first character may be an ASCII plus
 665      * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
 666      * integer value is returned.
 667      *
 668      * <p>An exception of type {@code NumberFormatException} is
 669      * thrown if any of the following situations occurs:
 670      * <ul>
 671      * <li>The first argument is {@code null} or is a string of
 672      * length zero.
 673      *
 674      * <li>The radix is either smaller than


 703 
 704         int len = s.length();
 705         if (len > 0) {
 706             char firstChar = s.charAt(0);
 707             if (firstChar == '-') {
 708                 throw new
 709                     NumberFormatException(String.format("Illegal leading minus sign " +
 710                                                        "on unsigned string %s.", s));
 711             } else {
 712                 if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
 713                     (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
 714                     return parseLong(s, radix);
 715                 }
 716 
 717                 // No need for range checks on len due to testing above.
 718                 long first = parseLong(s.substring(0, len - 1), radix);
 719                 int second = Character.digit(s.charAt(len - 1), radix);
 720                 if (second < 0) {
 721                     throw new NumberFormatException("Bad digit at end of " + s);
 722                 }
 723                 if (compareUnsigned(first, ParseUnsignedCache.div[radix]) > 0 ||
 724                         (first == ParseUnsignedCache.div[radix] &&
 725                         second > ParseUnsignedCache.rem[radix])) {
 726                     /*
 727                      * The maximum unsigned value, (2^64)-1, takes at
 728                      * most one more digit to represent than the
 729                      * maximum signed value, (2^63)-1.  Therefore,
 730                      * parsing (len - 1) digits will be appropriately
 731                      * in-range of the signed parsing.  In other
 732                      * words, if parsing (len -1) digits overflows
 733                      * signed parsing, parsing len digits will
 734                      * certainly overflow unsigned parsing.
 735                      *
 736                      * The compareUnsigned check above catches
 737                      * situations where an unsigned overflow occurs
 738                      * incorporating the contribution of the final
 739                      * digit.
 740                      */
 741                     throw new NumberFormatException(String.format("String value %s exceeds " +
 742                                                                   "range of unsigned long.", s));
 743                 }
 744                 return first * radix + second;
 745             }
 746         } else {
 747             throw NumberFormatException.forInputString(s);
 748         }
 749     }
 750 
 751     /**
 752      * Parses the string argument as an unsigned decimal {@code long}. The
 753      * characters in the string must all be decimal digits, except
 754      * that the first character may be an an ASCII plus sign {@code
 755      * '+'} ({@code '\u005Cu002B'}). The resulting integer value
 756      * is returned, exactly as if the argument and the radix 10 were
 757      * given as arguments to the {@link
 758      * #parseUnsignedLong(java.lang.String, int)} method.
 759      *
 760      * @param s   a {@code String} containing the unsigned {@code long}
 761      *            representation to be parsed
 762      * @return    the unsigned {@code long} value represented by the decimal string argument
 763      * @throws    NumberFormatException  if the string does not contain a
 764      *            parsable unsigned integer.