From 03c63863c7b31fbf4a5b00368aacd31b0221d62b Mon Sep 17 00:00:00 2001 From: Ramya Eliger Date: Sat, 8 Aug 2026 16:27:39 +0530 Subject: [PATCH] reject digit separator inside hex-float exponents --- double-conversion/string-to-double.cc | 23 +++++++++++++------- test/cctest/test-conversions.cc | 31 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/double-conversion/string-to-double.cc b/double-conversion/string-to-double.cc index c3309333..f6623954 100644 --- a/double-conversion/string-to-double.cc +++ b/double-conversion/string-to-double.cc @@ -251,14 +251,17 @@ static bool IsHexFloatString(Iterator start, } if (!saw_digit) return false; if (*current != 'p' && *current != 'P') return false; - if (Advance(¤t, separator, 16, end)) return false; + // The separator is only allowed between significand digits, not in the + // exponent, so advance through the exponent with no separator. + const uc16 kNoSeparator = StringToDoubleConverter::kNoSeparator; + if (Advance(¤t, kNoSeparator, 16, end)) return false; if (*current == '+' || *current == '-') { - if (Advance(¤t, separator, 16, end)) return false; + if (Advance(¤t, kNoSeparator, 16, end)) return false; } if (!isDigit(*current, 10)) return false; - if (Advance(¤t, separator, 16, end)) return true; + if (Advance(¤t, kNoSeparator, 16, end)) return true; while (isDigit(*current, 10)) { - if (Advance(¤t, separator, 16, end)) return true; + if (Advance(¤t, kNoSeparator, 16, end)) return true; } return allow_trailing_junk || !AdvanceToNonspace(¤t, end); } @@ -400,15 +403,19 @@ static double RadixStringToIeee(Iterator* current, if (parse_as_hex_float) { DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P'); - Advance(current, separator, radix, end); + // The separator is only allowed between significand digits, not in the + // exponent, so advance through the exponent with no separator. This must + // match IsHexFloatString, which validated the string the same way. + const uc16 kNoSeparator = StringToDoubleConverter::kNoSeparator; + Advance(current, kNoSeparator, radix, end); DOUBLE_CONVERSION_ASSERT(*current != end); bool is_negative = false; if (**current == '+') { - Advance(current, separator, radix, end); + Advance(current, kNoSeparator, radix, end); DOUBLE_CONVERSION_ASSERT(*current != end); } else if (**current == '-') { is_negative = true; - Advance(current, separator, radix, end); + Advance(current, kNoSeparator, radix, end); DOUBLE_CONVERSION_ASSERT(*current != end); } int written_exponent = 0; @@ -418,7 +425,7 @@ static double RadixStringToIeee(Iterator* current, if (abs(written_exponent) <= 100 * Double::kMaxExponent) { written_exponent = 10 * written_exponent + **current - '0'; } - if (Advance(current, separator, radix, end)) break; + if (Advance(current, kNoSeparator, radix, end)) break; } if (is_negative) written_exponent = -written_exponent; exponent += written_exponent; diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 12ce8bfb..cc873811 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -4091,6 +4091,37 @@ TEST(StringToDoubleSeparator) { StrToD16("0x0@3.p0", flags, 0.0, &processed, &all_used, char_separator, separator)); CHECK(all_used); + + // The separator is only allowed between significand digits, not in the + // exponent. The decimal exponent already rejects it; the hex-float exponent + // must reject it too. + separator = '_'; + flags = StringToDoubleConverter::ALLOW_HEX | + StringToDoubleConverter::ALLOW_HEX_FLOATS; + + CHECK_EQ(144.0, // 0x12p3, separator between significand digits. + StrToD("0x1_2p3", flags, 0.0, &processed, &all_used, separator)); + CHECK(all_used); + + CHECK_EQ(1024.0, // 0x1p10, no separator in the exponent. + StrToD("0x1p10", flags, 0.0, &processed, &all_used, separator)); + CHECK(all_used); + + CHECK_EQ(Double::NaN(), + StrToD("0x1p1_0", flags, 0.0, &processed, &all_used, separator)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), + StrToD("0x1.8p1_0", flags, 0.0, &processed, &all_used, separator)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), + StrToD("0x1p_10", flags, 0.0, &processed, &all_used, separator)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), + StrToD("0x1p10_", flags, 0.0, &processed, &all_used, separator)); + CHECK_EQ(0, processed); } TEST(StringToDoubleSpecialValues) {