From b5500e7957ba6838b1edf623e6d6f323988635e5 Mon Sep 17 00:00:00 2001 From: jdymitarai Date: Mon, 12 Oct 2026 14:29:25 +0900 Subject: [PATCH] preserve octal state for all-zero integer prefixes under ALLOW_OCTALS When StringToDoubleConverter is configured with ALLOW_OCTALS, strings starting with multiple zeros such as 00.5 or 00e2 were resetting octal to false because significant_digits was zero. This allowed decimal points and exponential suffixes to slip through into decimal parsing instead of being rejected or handled as trailing junk. We now track whether multiple leading zeros were consumed in the integer part, preserving octal mode when the integer part consists entirely of zeros while allowing single zero prefixes like 0.5 to parse as decimal numbers. In addition, parsing_done safely maps an empty octal buffer to SignedZero(sign) without triggering assertion failures. Regression test cases covering both strict and trailing junk modes for multi-zero and single-zero inputs have been added to test-conversions.cc, with all cctest test suites passing cleanly on Linux x86_64. --- double-conversion/string-to-double.cc | 36 ++++++++++++++++----------- test/cctest/test-conversions.cc | 22 ++++++++++++++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/double-conversion/string-to-double.cc b/double-conversion/string-to-double.cc index 41e647c4..d83d6ddb 100644 --- a/double-conversion/string-to-double.cc +++ b/double-conversion/string-to-double.cc @@ -670,6 +670,7 @@ double StringToDoubleConverter::StringToIeee( } bool leading_zero = false; + bool multiple_leading_zeros = false; if (*current == '0') { if (Advance(¤t, separator_, 10, end)) { *processed_characters_count = static_cast(current - input); @@ -716,6 +717,7 @@ double StringToDoubleConverter::StringToIeee( // Ignore leading zeros in the integer part. while (*current == '0') { + multiple_leading_zeros = true; if (Advance(¤t, separator_, 10, end)) { *processed_characters_count = static_cast(current - input); return SignedZero(sign); @@ -747,7 +749,9 @@ double StringToDoubleConverter::StringToIeee( } if (significant_digits == 0) { - octal = false; + if (!multiple_leading_zeros) { + octal = false; + } } if (*current == '.') { @@ -882,19 +886,23 @@ double StringToDoubleConverter::StringToIeee( if (octal) { double result; - bool result_is_junk; - char* start = buffer; - result = RadixStringToIeee<3>(&start, - buffer + buffer_pos, - sign, - separator_, - false, // Don't parse as hex_float. - allow_trailing_junk, - allow_trailing_spaces, - junk_string_value_, - read_as_double, - &result_is_junk); - DOUBLE_CONVERSION_ASSERT(!result_is_junk); + if (buffer_pos == 0) { + result = SignedZero(sign); + } else { + bool result_is_junk; + char* start = buffer; + result = RadixStringToIeee<3>(&start, + buffer + buffer_pos, + sign, + separator_, + false, // Don't parse as hex_float. + allow_trailing_junk, + allow_trailing_spaces, + junk_string_value_, + read_as_double, + &result_is_junk); + DOUBLE_CONVERSION_ASSERT(!result_is_junk); + } *processed_characters_count = static_cast(current - input); return result; } diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 0daf7919..7e41dcb8 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -3596,6 +3596,20 @@ TEST(StringToDoubleOctalString) { StrToD("01234567e0", flags, Double::NaN(), &processed, &all_used)); CHECK_EQ(0, processed); + CHECK_EQ(Double::NaN(), + StrToD("00.5", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(Double::NaN(), + StrToD("00e2", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(0, processed); + + CHECK_EQ(0.5, StrToD("0.5", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + + CHECK_EQ(8.5, StrToD("008.5", flags, Double::NaN(), &processed, &all_used)); + CHECK(all_used); + flags = StringToDoubleConverter::ALLOW_OCTALS | StringToDoubleConverter::ALLOW_TRAILING_JUNK; @@ -3753,6 +3767,14 @@ TEST(StringToDoubleOctalString) { StrToD("01234567e", flags, Double::NaN(), &processed, &all_used)); CHECK_EQ(8, processed); + CHECK_EQ(0.0, + StrToD("00.5", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(2, processed); + + CHECK_EQ(0.0, + StrToD("00e2", flags, Double::NaN(), &processed, &all_used)); + CHECK_EQ(2, processed); + flags = StringToDoubleConverter::ALLOW_OCTALS | StringToDoubleConverter::ALLOW_TRAILING_SPACES | StringToDoubleConverter::ALLOW_TRAILING_JUNK;