Skip to content

Commit cdb4dfc

Browse files
committed
Merge bitcoin/bitcoin#20452: util: Replace use of locale dependent atoi(…) with locale-independent std::from_chars(…) (C++17)
4343f11 Replace use of locale dependent atoi(…) with locale-independent std::from_chars(…) (C++17) (practicalswift) Pull request description: Replace use of locale dependent `atoi(…)` with locale-independent `std::from_chars(…)` (C++17). ACKs for top commit: laanwj: Code review ACK 4343f11 jonatack: Code review ACK 4343f11 Tree-SHA512: e4909da282b6cefc5ca34e13b02cc489af56cab339a77ae5c35ac9ef355d9b941b129a2bfddc1b37426b11c79a21c8b729fbb5255e6d9eaa344406b18b825494
2 parents c6f710e + 4343f11 commit cdb4dfc

15 files changed

+145
-52
lines changed

src/core_read.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ CScript ParseScript(const std::string& s)
6969
(w->front() == '-' && w->size() > 1 && std::all_of(w->begin()+1, w->end(), ::IsDigit)))
7070
{
7171
// Number
72-
int64_t n = atoi64(*w);
72+
int64_t n = LocaleIndependentAtoi<int64_t>(*w);
7373

7474
//limit the range of numbers ParseScript accepts in decimal
7575
//since numbers outside -0xFFFFFFFF...0xFFFFFFFF are illegal in scripts

src/node/blockstorage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void CleanupBlockRevFiles()
8585
// start removing block files.
8686
int nContigCounter = 0;
8787
for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
88-
if (atoi(item.first) == nContigCounter) {
88+
if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {
8989
nContigCounter++;
9090
continue;
9191
}

src/qt/rpcconsole.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
250250
for(char argch: curarg)
251251
if (!IsDigit(argch))
252252
throw std::runtime_error("Invalid result query");
253-
subelement = lastResult[atoi(curarg.c_str())];
253+
subelement = lastResult[LocaleIndependentAtoi<int>(curarg)];
254254
}
255255
else if (lastResult.isObject())
256256
subelement = find_value(lastResult, curarg);

src/rpc/mining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ static RPCHelpMan getblocktemplate()
702702
std::string lpstr = lpval.get_str();
703703

704704
hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid");
705-
nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
705+
nTransactionsUpdatedLastLP = LocaleIndependentAtoi<int64_t>(lpstr.substr(64));
706706
}
707707
else
708708
{

src/test/fuzz/locale.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ FUZZ_TARGET(locale)
5050
const bool parseint32_without_locale = ParseInt32(random_string, &parseint32_out_without_locale);
5151
int64_t parseint64_out_without_locale;
5252
const bool parseint64_without_locale = ParseInt64(random_string, &parseint64_out_without_locale);
53-
const int64_t atoi64_without_locale = atoi64(random_string);
54-
const int atoi_without_locale = atoi(random_string);
5553
const int64_t random_int64 = fuzzed_data_provider.ConsumeIntegral<int64_t>();
5654
const std::string tostring_without_locale = ToString(random_int64);
5755
// The variable `random_int32` is no longer used, but the harness still needs to
@@ -77,10 +75,6 @@ FUZZ_TARGET(locale)
7775
if (parseint64_without_locale) {
7876
assert(parseint64_out_without_locale == parseint64_out_with_locale);
7977
}
80-
const int64_t atoi64_with_locale = atoi64(random_string);
81-
assert(atoi64_without_locale == atoi64_with_locale);
82-
const int atoi_with_locale = atoi(random_string);
83-
assert(atoi_without_locale == atoi_with_locale);
8478
const std::string tostring_with_locale = ToString(random_int64);
8579
assert(tostring_without_locale == tostring_with_locale);
8680
const std::string strprintf_int_with_locale = strprintf("%d", random_int64);

src/test/fuzz/parse_numbers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ FUZZ_TARGET(parse_numbers)
2525

2626
int32_t i32;
2727
(void)ParseInt32(random_string, &i32);
28-
(void)atoi(random_string);
28+
(void)LocaleIndependentAtoi<int>(random_string);
2929

3030
uint32_t u32;
3131
(void)ParseUInt32(random_string, &u32);
3232

3333
int64_t i64;
34-
(void)atoi64(random_string);
34+
(void)LocaleIndependentAtoi<int64_t>(random_string);
3535
(void)ParseFixedPoint(random_string, 3, &i64);
3636
(void)ParseInt64(random_string, &i64);
3737

src/test/fuzz/string.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ bool LegacyParseUInt64(const std::string& str, uint64_t* out)
122122
return endp && *endp == 0 && !errno &&
123123
n <= std::numeric_limits<uint64_t>::max();
124124
}
125+
126+
// For backwards compatibility checking.
127+
int64_t atoi64_legacy(const std::string& str)
128+
{
129+
return strtoll(str.c_str(), nullptr, 10);
130+
}
125131
}; // namespace
126132

127133
FUZZ_TARGET(string)
@@ -268,4 +274,22 @@ FUZZ_TARGET(string)
268274
assert(u8 == u8_legacy);
269275
}
270276
}
277+
278+
{
279+
const int atoi_result = atoi(random_string_1.c_str());
280+
const int locale_independent_atoi_result = LocaleIndependentAtoi<int>(random_string_1);
281+
const int64_t atoi64_result = atoi64_legacy(random_string_1);
282+
const bool out_of_range = atoi64_result < std::numeric_limits<int>::min() || atoi64_result > std::numeric_limits<int>::max();
283+
if (out_of_range) {
284+
assert(locale_independent_atoi_result == 0);
285+
} else {
286+
assert(atoi_result == locale_independent_atoi_result);
287+
}
288+
}
289+
290+
{
291+
const int64_t atoi64_result = atoi64_legacy(random_string_1);
292+
const int64_t locale_independent_atoi_result = LocaleIndependentAtoi<int64_t>(random_string_1);
293+
assert(atoi64_result == locale_independent_atoi_result || locale_independent_atoi_result == 0);
294+
}
271295
}

src/test/util_tests.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,77 @@ BOOST_AUTO_TEST_CASE(test_ToIntegral)
15491549
BOOST_CHECK(!ToIntegral<uint8_t>("256"));
15501550
}
15511551

1552+
BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi)
1553+
{
1554+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1234"), 1'234);
1555+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("0"), 0);
1556+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("01234"), 1'234);
1557+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-1234"), -1'234);
1558+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(" 1"), 1);
1559+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1 "), 1);
1560+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1a"), 1);
1561+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1.1"), 1);
1562+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1.9"), 1);
1563+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("+01.9"), 1);
1564+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-1"), -1);
1565+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(" -1"), -1);
1566+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-1 "), -1);
1567+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(" -1 "), -1);
1568+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("+1"), 1);
1569+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(" +1"), 1);
1570+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(" +1 "), 1);
1571+
1572+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("+-1"), 0);
1573+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-+1"), 0);
1574+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("++1"), 0);
1575+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("--1"), 0);
1576+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(""), 0);
1577+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("aap"), 0);
1578+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("0x1"), 0);
1579+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-32482348723847471234"), 0);
1580+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("32482348723847471234"), 0);
1581+
1582+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775809"), 0);
1583+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775808"), -9'223'372'036'854'775'807LL - 1LL);
1584+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775807"), 9'223'372'036'854'775'807);
1585+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775808"), 0);
1586+
1587+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("-1"), 0U);
1588+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("0"), 0U);
1589+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551615"), 18'446'744'073'709'551'615ULL);
1590+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551616"), 0U);
1591+
1592+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483649"), 0);
1593+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483648"), -2'147'483'648LL);
1594+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483647"), 2'147'483'647);
1595+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483648"), 0);
1596+
1597+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("-1"), 0U);
1598+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("0"), 0U);
1599+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967295"), 4'294'967'295U);
1600+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967296"), 0U);
1601+
1602+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32769"), 0);
1603+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32768"), -32'768);
1604+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32767"), 32'767);
1605+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32768"), 0);
1606+
1607+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("-1"), 0U);
1608+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("0"), 0U);
1609+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65535"), 65'535U);
1610+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65536"), 0U);
1611+
1612+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-129"), 0);
1613+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-128"), -128);
1614+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("127"), 127);
1615+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("128"), 0);
1616+
1617+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("-1"), 0U);
1618+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("0"), 0U);
1619+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("255"), 255U);
1620+
BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 0U);
1621+
}
1622+
15521623
BOOST_AUTO_TEST_CASE(test_ParseInt64)
15531624
{
15541625
int64_t n;

src/torcontrol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ void TorControlConnection::readcb(struct bufferevent *bev, void *ctx)
8383
if (s.size() < 4) // Short line
8484
continue;
8585
// <status>(-|+| )<data><CRLF>
86-
self->message.code = atoi(s.substr(0,3));
86+
self->message.code = LocaleIndependentAtoi<int>(s.substr(0,3));
8787
self->message.lines.push_back(s.substr(4));
8888
char ch = s[3]; // '-','+' or ' '
8989
if (ch == ' ') {

src/util/moneystr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ std::optional<CAmount> ParseMoney(const std::string& money_string)
7777
return std::nullopt;
7878
if (nUnits < 0 || nUnits > COIN)
7979
return std::nullopt;
80-
int64_t nWhole = atoi64(strWhole);
81-
80+
int64_t nWhole = LocaleIndependentAtoi<int64_t>(strWhole);
8281
CAmount value = nWhole * COIN + nUnits;
8382

8483
if (!MoneyRange(value)) {

0 commit comments

Comments
 (0)