From 6bb5dfe2d97c13f05cf21e60c62735ee5a32a4ca Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 28 Oct 2018 06:48:46 -0400 Subject: [PATCH] Merge #14585: refactor: remove usage of locale dependent std::isspace 15db77f4dd Don't rely on locale dependent functions in base_blob::SetHex(...) (uint256), DecodeBase58(...), ParseMoney(...) and ParseHex(...) (practicalswift) Pull request description: Don't rely on locale dependent function `std::isspace` in `base_blob::SetHex(...)` (uint256), `DecodeBase58(...)`, `ParseMoney(...)` and `ParseHex(...)`. Rationale: ``` $ uname -s Darwin $ cat poc.cpp #include #include int main(void) { setlocale(LC_ALL, ""); std::cout << std::isspace(133) << ' ' << std::isspace(154) << ' ' << std::isspace(160); std::cout << '\n'; } $ clang++ -o poc poc.cpp $ ./poc 1 0 1 $ LC_ALL=en_US ./poc 1 0 1 $ LC_ALL=C ./poc 0 0 0 $ LC_ALL=ru_RU.KOI8-R ./poc # an "interesting" locale 0 1 0 ``` Tree-SHA512: 4eafb267342b8a777da6cca07c353afd1f90f3fc1d91e01f526f1b384a2b97c1da25b7bd7dfc300655182a4eaec6a4bea855a45723ab53c750a734b60e1e3c9f --- src/base58.cpp | 6 +++--- src/uint256.cpp | 2 +- src/util/moneystr.cpp | 6 +++--- src/util/strencodings.cpp | 4 ++-- src/util/strencodings.h | 15 +++++++++++++++ test/lint/lint-locale-dependence.sh | 4 ---- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 306547ce1e..849293634a 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -36,7 +36,7 @@ static const int8_t mapBase58[256] = { bool DecodeBase58(const char* psz, std::vector& vch) { // Skip leading spaces. - while (*psz && isspace(*psz)) + while (*psz && IsSpace(*psz)) psz++; // Skip and count leading '1's. int zeroes = 0; @@ -50,7 +50,7 @@ bool DecodeBase58(const char* psz, std::vector& vch) std::vector b256(size); // Process the characters. static_assert(sizeof(mapBase58)/sizeof(mapBase58[0]) == 256, "mapBase58.size() should be 256"); // guarantee not out of range - while (*psz && !isspace(*psz)) { + while (*psz && !IsSpace(*psz)) { // Decode base58 character int carry = mapBase58[(uint8_t)*psz]; if (carry == -1) // Invalid b58 character @@ -66,7 +66,7 @@ bool DecodeBase58(const char* psz, std::vector& vch) psz++; } // Skip trailing spaces. - while (isspace(*psz)) + while (IsSpace(*psz)) psz++; if (*psz != 0) return false; diff --git a/src/uint256.cpp b/src/uint256.cpp index dfd9218b86..e82c794382 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -33,7 +33,7 @@ void base_blob::SetHex(const char* psz) memset(m_data, 0, sizeof(m_data)); // skip leading spaces - while (isspace(*psz)) + while (IsSpace(*psz)) psz++; // skip 0x diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp index bc376f1dc1..467a142ad0 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -41,7 +41,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) std::string strWhole; int64_t nUnits = 0; const char* p = pszIn; - while (isspace(*p)) + while (IsSpace(*p)) p++; for (; *p; p++) { @@ -56,14 +56,14 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) } break; } - if (isspace(*p)) + if (IsSpace(*p)) break; if (!isdigit(*p)) return false; strWhole.insert(strWhole.end(), *p); } for (; *p; p++) - if (!isspace(*p)) + if (!IsSpace(*p)) return false; if (strWhole.size() > 10) // guard against 63 bit overflow return false; diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 27d757ef46..9481ca4573 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -87,7 +87,7 @@ std::vector ParseHex(const char* psz) std::vector vch; while (true) { - while (isspace(*psz)) + while (IsSpace(*psz)) psz++; signed char c = HexDigit(*psz++); if (c == (signed char)-1) @@ -272,7 +272,7 @@ std::string DecodeBase32(const std::string& str, bool* pf_invalid) { if (str.empty()) // No empty string allowed return false; - if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed + 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; diff --git a/src/util/strencodings.h b/src/util/strencodings.h index f4a359854f..79a5937713 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -84,6 +84,21 @@ constexpr bool IsDigit(char c) return c >= '0' && c <= '9'; } +/** + * Tests if the given character is a whitespace character. The whitespace characters + * are: space, form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal + * tab ('\t'), and vertical tab ('\v'). + * + * This function is locale independent. Under the C locale this function gives the + * same result as std::isspace. + * + * @param[in] c character to test + * @return true if the argument is a whitespace character; otherwise false + */ +constexpr inline bool IsSpace(char c) noexcept { + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; +} + /** * Convert string to signed 32-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index cd6e93eb32..a06c8afc79 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -3,7 +3,6 @@ export LC_ALL=C KNOWN_VIOLATIONS=( - "src/base58.cpp:.*isspace" "src/bench/string_cast.cpp.*atoi" "src/dash-tx.cpp.*stoul" "src/dash-tx.cpp.*trim_right" @@ -29,14 +28,11 @@ KNOWN_VIOLATIONS=( "src/test/getarg_tests.cpp.*split" "src/torcontrol.cpp:.*atoi" "src/torcontrol.cpp:.*strtol" - "src/uint256.cpp:.*isspace" "src/uint256.cpp:.*tolower" "src/util/system.cpp:.*atoi" "src/util/system.cpp:.*tolower" "src/util/moneystr.cpp:.*isdigit" - "src/util/moneystr.cpp:.*isspace" "src/util/strencodings.cpp:.*atoi" - "src/util/strencodings.cpp:.*isspace" "src/util/strencodings.cpp:.*strtol" "src/util/strencodings.cpp:.*strtoll" "src/util/strencodings.cpp:.*strtoul"