Skip to content

Commit

Permalink
Merge bitcoin/bitcoin#23156: refactor: Remove unused ParsePrechecks a…
Browse files Browse the repository at this point in the history
…nd ParseDouble

fa9d72a Remove unused ParseDouble and ParsePrechecks (MarcoFalke)
fa3cd28 refactor: Remove unused ParsePrechecks from ParseIntegral (MarcoFalke)

Pull request description:

  All of the `ParsePrechecks` are already done by `ToIntegral`, so remove them from `ParseIntegral`.

  Also:
  * Remove redundant `{}`. See bitcoin/bitcoin#20457 (comment)
  * Add missing failing c-string test case
  * Add missing failing test cases for non-int32_t integral types

ACKs for top commit:
  laanwj:
    Code review ACK fa9d72a, good find on ParseDouble not being used at all, and testing for behavior of embedded NULL characters is always a good thing.
  practicalswift:
    cr ACK fa9d72a

Tree-SHA512: 3d654dcaebbf312dd57e54241f9aa6d35b1d1d213c37e4c6b8b9a69bcbe8267a397474a8b86b57740fbdd8e3d03b4cdb6a189a9eb8e05cd38035dab195410aa7
  • Loading branch information
MarcoFalke committed Oct 4, 2021
2 parents cdb4dfc + fa9d72a commit 42fedb4
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 89 deletions.
3 changes: 0 additions & 3 deletions src/test/fuzz/parse_numbers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ FUZZ_TARGET(parse_numbers)

(void)ParseMoney(random_string);

double d;
(void)ParseDouble(random_string, &d);

uint8_t u8;
(void)ParseUInt8(random_string, &u8);

Expand Down
84 changes: 37 additions & 47 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,35 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("32482348723847471234", nullptr));
}

template <typename T>
static void RunToIntegralTests()
{
BOOST_CHECK(!ToIntegral<T>(STRING_WITH_EMBEDDED_NULL_CHAR));
BOOST_CHECK(!ToIntegral<T>(" 1"));
BOOST_CHECK(!ToIntegral<T>("1 "));
BOOST_CHECK(!ToIntegral<T>("1a"));
BOOST_CHECK(!ToIntegral<T>("1.1"));
BOOST_CHECK(!ToIntegral<T>("1.9"));
BOOST_CHECK(!ToIntegral<T>("+01.9"));
BOOST_CHECK(!ToIntegral<T>("-"));
BOOST_CHECK(!ToIntegral<T>("+"));
BOOST_CHECK(!ToIntegral<T>(" -1"));
BOOST_CHECK(!ToIntegral<T>("-1 "));
BOOST_CHECK(!ToIntegral<T>(" -1 "));
BOOST_CHECK(!ToIntegral<T>("+1"));
BOOST_CHECK(!ToIntegral<T>(" +1"));
BOOST_CHECK(!ToIntegral<T>(" +1 "));
BOOST_CHECK(!ToIntegral<T>("+-1"));
BOOST_CHECK(!ToIntegral<T>("-+1"));
BOOST_CHECK(!ToIntegral<T>("++1"));
BOOST_CHECK(!ToIntegral<T>("--1"));
BOOST_CHECK(!ToIntegral<T>(""));
BOOST_CHECK(!ToIntegral<T>("aap"));
BOOST_CHECK(!ToIntegral<T>("0x1"));
BOOST_CHECK(!ToIntegral<T>("-32482348723847471234"));
BOOST_CHECK(!ToIntegral<T>("32482348723847471234"));
}

BOOST_AUTO_TEST_CASE(test_ToIntegral)
{
BOOST_CHECK_EQUAL(ToIntegral<int32_t>("1234").value(), 1'234);
Expand All @@ -1486,27 +1515,14 @@ BOOST_AUTO_TEST_CASE(test_ToIntegral)
BOOST_CHECK_EQUAL(ToIntegral<int32_t>("-1234").value(), -1'234);
BOOST_CHECK_EQUAL(ToIntegral<int32_t>("-1").value(), -1);

BOOST_CHECK(!ToIntegral<int32_t>(" 1"));
BOOST_CHECK(!ToIntegral<int32_t>("1 "));
BOOST_CHECK(!ToIntegral<int32_t>("1a"));
BOOST_CHECK(!ToIntegral<int32_t>("1.1"));
BOOST_CHECK(!ToIntegral<int32_t>("1.9"));
BOOST_CHECK(!ToIntegral<int32_t>("+01.9"));
BOOST_CHECK(!ToIntegral<int32_t>(" -1"));
BOOST_CHECK(!ToIntegral<int32_t>("-1 "));
BOOST_CHECK(!ToIntegral<int32_t>(" -1 "));
BOOST_CHECK(!ToIntegral<int32_t>("+1"));
BOOST_CHECK(!ToIntegral<int32_t>(" +1"));
BOOST_CHECK(!ToIntegral<int32_t>(" +1 "));
BOOST_CHECK(!ToIntegral<int32_t>("+-1"));
BOOST_CHECK(!ToIntegral<int32_t>("-+1"));
BOOST_CHECK(!ToIntegral<int32_t>("++1"));
BOOST_CHECK(!ToIntegral<int32_t>("--1"));
BOOST_CHECK(!ToIntegral<int32_t>(""));
BOOST_CHECK(!ToIntegral<int32_t>("aap"));
BOOST_CHECK(!ToIntegral<int32_t>("0x1"));
BOOST_CHECK(!ToIntegral<int32_t>("-32482348723847471234"));
BOOST_CHECK(!ToIntegral<int32_t>("32482348723847471234"));
RunToIntegralTests<uint64_t>();
RunToIntegralTests<int64_t>();
RunToIntegralTests<uint32_t>();
RunToIntegralTests<int32_t>();
RunToIntegralTests<uint16_t>();
RunToIntegralTests<int16_t>();
RunToIntegralTests<uint8_t>();
RunToIntegralTests<int8_t>();

BOOST_CHECK(!ToIntegral<int64_t>("-9223372036854775809"));
BOOST_CHECK_EQUAL(ToIntegral<int64_t>("-9223372036854775808").value(), -9'223'372'036'854'775'807LL - 1LL);
Expand Down Expand Up @@ -1785,32 +1801,6 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt64)
BOOST_CHECK(!ParseUInt64("-1234", &n));
}

BOOST_AUTO_TEST_CASE(test_ParseDouble)
{
double n;
// Valid values
BOOST_CHECK(ParseDouble("1234", nullptr));
BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
// Invalid values
BOOST_CHECK(!ParseDouble("", &n));
BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
BOOST_CHECK(!ParseDouble("1 ", &n));
BOOST_CHECK(!ParseDouble("1a", &n));
BOOST_CHECK(!ParseDouble("aap", &n));
BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
BOOST_CHECK(!ParseDouble(STRING_WITH_EMBEDDED_NULL_CHAR, &n));
// Overflow and underflow
BOOST_CHECK(!ParseDouble("-1e10000", nullptr));
BOOST_CHECK(!ParseDouble("1e10000", nullptr));
}

BOOST_AUTO_TEST_CASE(test_FormatParagraph)
{
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
Expand Down
30 changes: 0 additions & 30 deletions src/util/strencodings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,16 +281,11 @@ std::string DecodeBase32(const std::string& str, bool* pf_invalid)
return std::string((const char*)vchRet.data(), vchRet.size());
}

[[nodiscard]] static bool ParsePrechecks(const std::string&);

namespace {
template <typename T>
bool ParseIntegral(const std::string& str, T* out)
{
static_assert(std::is_integral<T>::value);
if (!ParsePrechecks(str)) {
return false;
}
// Replicate the exact behavior of strtol/strtoll/strtoul/strtoull when
// handling leading +/- for backwards compatibility.
if (str.length() >= 2 && str[0] == '+' && str[1] == '-') {
Expand All @@ -307,17 +302,6 @@ bool ParseIntegral(const std::string& str, T* out)
}
}; // namespace

[[nodiscard]] static bool ParsePrechecks(const std::string& str)
{
if (str.empty()) // No empty string allowed
return false;
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size()-1]))) // No padding allowed
return false;
if (!ValidAsCString(str)) // No embedded NUL characters allowed
return false;
return true;
}

bool ParseInt32(const std::string& str, int32_t* out)
{
return ParseIntegral<int32_t>(str, out);
Expand Down Expand Up @@ -348,20 +332,6 @@ bool ParseUInt64(const std::string& str, uint64_t* out)
return ParseIntegral<uint64_t>(str, out);
}

bool ParseDouble(const std::string& str, double *out)
{
if (!ParsePrechecks(str))
return false;
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
return false;
std::istringstream text(str);
text.imbue(std::locale::classic());
double result;
text >> result;
if(out) *out = result;
return text.eof() && !text.fail();
}

std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
{
std::stringstream out;
Expand Down
13 changes: 4 additions & 9 deletions src/util/strencodings.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ constexpr inline bool IsSpace(char c) noexcept {
}

/**
* Convert string to integral type T.
* Convert string to integral type T. Leading whitespace, a leading +, or any
* trailing character fail the parsing. The required format expressed as regex
* is `-?[0-9]+`.
*
* @returns std::nullopt if the entire string could not be parsed, or if the
* parsed value is not in the range representable by the type T.
Expand All @@ -137,7 +139,7 @@ std::optional<T> ToIntegral(const std::string& str)
if (first_nonmatching != str.data() + str.size() || error_condition != std::errc{}) {
return std::nullopt;
}
return {result};
return result;
}

/**
Expand Down Expand Up @@ -182,13 +184,6 @@ std::optional<T> ToIntegral(const std::string& str)
*/
[[nodiscard]] bool ParseUInt64(const std::string& str, uint64_t *out);

/**
* Convert string to double with strict parse error feedback.
* @returns true if the entire string could be parsed as valid double,
* false if not the entire string could be parsed or when overflow or underflow occurred.
*/
[[nodiscard]] bool ParseDouble(const std::string& str, double *out);

/**
* Convert a span of bytes to a lower-case hexadecimal string.
*/
Expand Down

0 comments on commit 42fedb4

Please sign in to comment.