Bug in Long.parseUnsignedLong
Paul Sandoz
paul.sandoz at oracle.com
Thu Dec 19 17:36:12 UTC 2013
Hi,
I think the logic for overflow when using the compareUnsigned is incorrect in Long:
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) {
Take for example a string representation consisting of 17 digits "12000000000000000"
The long that will be parsed is one char less "1200000000000000":
first = 0x1200_0000_0000_0000
second = 0;
result = 0x2000_0000_0000_0000 // first << 4, result > first
i.e. overflow of the overflow if you consider 16 additions, rather than a multiply.
My brain is too clogged up with cold at the moment to propose a fix :-(
Paul.
On Dec 19, 2013, at 12:52 AM, Louis Wasserman <lowasser at google.com> wrote:
> Derp. Here is the test case:
>
> import java.math.BigInteger;
>
> public class UnsignedLongBug {
> public static void main(String[] args) {
> try {
> String input = "1234567890abcdef1";
> System.out.println(Long.parseUnsignedLong(input, 16));
> BigInteger maxUnsignedLong =
> BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE);
> BigInteger inputValue = new BigInteger(input, 16);
> System.out.println(maxUnsignedLong.compareTo(inputValue));
> throw new AssertionError();
> } catch (NumberFormatException expected) {
> System.out.println("Correct");
> }
> }
> }
>
>
> On Wed, Dec 18, 2013 at 3:51 PM, Louis Wasserman <lowasser at google.com>wrote:
>
>> The Javadoc of Long.parseUnsignedLong specifies that it should throw a
>> NumberFormatException if "the value represented by the string is larger
>> than the largest unsigned long, 2^64-1."
>>
>> This does not appear to be happening:
>>
>> --
>> Louis Wasserman
>>
>
>
>
> --
> Louis Wasserman
More information about the core-libs-dev
mailing list