Fix some issues with invalid hex-float literals.
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.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2a06c71..02c34e3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/Changelog b/Changelog
index 647a0d8..606f47f 100644
--- a/Changelog
+++ b/Changelog
@@ -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.
diff --git a/double-conversion/double-conversion.cc b/double-conversion/double-conversion.cc
index 163d41b..6da28ed 100644
--- a/double-conversion/double-conversion.cc
+++ b/double-conversion/double-conversion.cc
@@ -604,8 +604,8 @@
saw_digit = true;
if (Advance(¤t, 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(¤t, separator, 16, end)) return false;
if (*current == '+' || *current == '-') {
@@ -763,7 +763,11 @@
}
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;
@@ -899,10 +903,11 @@
(*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_;
}
diff --git a/double-conversion/ieee.h b/double-conversion/ieee.h
index 4a5fe8f..8327484 100644
--- a/double-conversion/ieee.h
+++ b/double-conversion/ieee.h
@@ -47,6 +47,8 @@
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)) {}
@@ -222,9 +224,7 @@
}
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);
diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc
index 878fd0f..014dd5e 100644
--- a/test/cctest/test-conversions.cc
+++ b/test/cctest/test-conversions.cc
@@ -2682,6 +2682,71 @@
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);
}
@@ -4669,6 +4734,156 @@
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);
}