Skip to content

Commit

Permalink
Fix some issues with invalid hex-float literals.
Browse files Browse the repository at this point in the history
When converting `0x` the converter would assert (or access out of
    boundary).
With `0x1.p1234556666FFFFF` the converter would overflow and not yield
the correct exponent.
  • Loading branch information
floitsch committed May 25, 2019
1 parent fb2364d commit 5fa81e8
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 6 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.0)
project(double-conversion VERSION 3.1.4)
project(double-conversion VERSION 3.1.5)

set(headers
double-conversion/bignum.h
Expand Down
5 changes: 5 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2019-05-25:
Fix `0x` for string->double conversion when Hex Floats are allowed.
Avoid integer overflow when exponents for hex floats were too big.
Update version number.

2019-04-22:
Fixed warning in gcc4.9. Thanks to Scott McCaskill
(https://github.com/usefulcat) for the patch.
Expand Down
11 changes: 8 additions & 3 deletions double-conversion/double-conversion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,8 @@ static bool IsHexFloatString(Iterator start,
saw_digit = true;
if (Advance(&current, separator, 16, end)) return false;
}
if (!saw_digit) return false; // Only the '.', but no digits.
}
if (!saw_digit) return false;
if (*current != 'p' && *current != 'P') return false;
if (Advance(&current, separator, 16, end)) return false;
if (*current == '+' || *current == '-') {
Expand Down Expand Up @@ -763,7 +763,11 @@ static double RadixStringToIeee(Iterator* current,
}
int written_exponent = 0;
while (IsDecimalDigitForRadix(**current, 10)) {
written_exponent = 10 * written_exponent + **current - '0';
// No need to read exponents if they are too big. That could potentially overflow
// the `written_exponent` variable.
if (abs(written_exponent) <= 100 * Double::kMaxExponent) {
written_exponent = 10 * written_exponent + **current - '0';
}
if (Advance(current, separator, radix, end)) break;
}
if (is_negative) written_exponent = -written_exponent;
Expand Down Expand Up @@ -899,10 +903,11 @@ double StringToDoubleConverter::StringToIeee(
(*current == 'x' || *current == 'X')) {
++current;

if (current == end) return junk_string_value_; // "0x"

bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) &&
IsHexFloatString(current, end, separator_, allow_trailing_junk);

if (current == end) return junk_string_value_; // "0x"
if (!parse_as_hex_float && !isDigit(*current, 16)) {
return junk_string_value_;
}
Expand Down
4 changes: 2 additions & 2 deletions double-conversion/ieee.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class Double {
static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
static const int kSignificandSize = 53;
static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
static const int kMaxExponent = 0x7FF - kExponentBias;

Double() : d64_(0) {}
explicit Double(double d) : d64_(double_to_uint64(d)) {}
Expand Down Expand Up @@ -222,9 +224,7 @@ class Double {
}

private:
static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
static const int kDenormalExponent = -kExponentBias + 1;
static const int kMaxExponent = 0x7FF - kExponentBias;
static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);

Expand Down
215 changes: 215 additions & 0 deletions test/cctest/test-conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,71 @@ TEST(StringToDoubleHexString) {

CHECK_EQ(-0.0, StrToD("-0x1p-2000", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(Double::NaN(), StrToD(" ", flags, Double::NaN(),
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("0x", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD(" 0x ", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD(" 0x 3", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("0x3g", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("x3", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD(" 0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("+ 0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("+", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("-", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("- -0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("- +0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("+ +0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("0xp1", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::NaN(), StrToD("0x.p1", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Double::Infinity(), StrToD("0x1.p10000000000000000", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(0.0, StrToD("0x1.p-10000000000000000", flags, 0.0,
&processed, &all_used));
CHECK(all_used);
}


Expand Down Expand Up @@ -4669,6 +4734,156 @@ TEST(StringToFloatHexString) {
CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0f,
&processed, &all_used));
CHECK_EQ(0, processed);

flags = StringToDoubleConverter::ALLOW_HEX_FLOATS;

CHECK_EQ(3.0f, StrToF("0x3p0", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(0.0f, StrToF("0x.0p0", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(3.0f, StrToF("0x3.0p0", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(3.0f, StrToF("0x3.p0", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(-5634002804104940178441764864.0f, StrToF("-0x123456789012345678901234p0",
flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(134217728.0f, StrToF("0x8000001p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(134217728.0f, StrToF("0x8000000p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755813888.0f, StrToF("0x8000000001p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755813888.0f, StrToF("0x8000000000p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755879424.0f, StrToF("0x8000008001p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755813888.0f, StrToF("0x8000008000p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755944960.0f, StrToF("0x8000018001p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(549755944960.0f, StrToF("0x8000018000p0", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(8796093022208.0f, StrToF("0x8000000001p4", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(8796093022208.0f, StrToF("0x8000000000p+4", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(8796094070784.0f, StrToF("0x8000008001p04", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(34359738368.0f, StrToF("0x8000008000p-4", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(34359746560.0f, StrToF("0x8000018001p-04", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(8796095119360.0f, StrToF("0x8000018000p4", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(Single::Infinity(), StrToF("0x1p2000", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(0.0f, StrToF("0x1p-2000", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(-0.0f, StrToF("-0x1p-2000", flags, 0.0, &processed, &all_used));
CHECK(all_used);

CHECK_EQ(Single::NaN(), StrToF(" ", flags, Single::NaN(),
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("0x", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF(" 0x ", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF(" 0x 3", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("0x3g", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("x3", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF(" 0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("+ 0x3 foo", flags, 0.0,
&processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("+", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("-", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("- -0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("- +0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("+ +0x5", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("0xp1", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::NaN(), StrToF("0x.p1", flags, 0.0, &processed, &all_used));
CHECK_EQ(0, processed);

CHECK_EQ(Single::Infinity(), StrToF("0x1.p10000000000000000", flags, 0.0,
&processed, &all_used));
CHECK(all_used);

CHECK_EQ(0.0f, StrToF("0x1.p-10000000000000000", flags, 0.0,
&processed, &all_used));
CHECK(all_used);
}


Expand Down

0 comments on commit 5fa81e8

Please sign in to comment.