diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/httpserver.cpp | 10 | ||||
-rw-r--r-- | src/qt/bitcoin.cpp | 5 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 7 | ||||
-rw-r--r-- | src/qt/guiconstants.h | 10 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 12 | ||||
-rw-r--r-- | src/qt/guiutil.h | 4 | ||||
-rw-r--r-- | src/qt/intro.cpp | 10 | ||||
-rw-r--r-- | src/qt/optionsdialog.cpp | 4 | ||||
-rw-r--r-- | src/qt/optionsmodel.cpp | 4 | ||||
-rw-r--r-- | src/qt/paymentserver.cpp | 2 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 5 | ||||
-rw-r--r-- | src/qt/test/addressbooktests.cpp | 4 | ||||
-rw-r--r-- | src/qt/test/util.cpp | 4 | ||||
-rw-r--r-- | src/qt/test/util.h | 8 | ||||
-rw-r--r-- | src/qt/test/wallettests.cpp | 3 | ||||
-rw-r--r-- | src/qt/transactionview.cpp | 5 | ||||
-rw-r--r-- | src/qt/walletcontroller.cpp | 5 | ||||
-rw-r--r-- | src/test/fuzz/coins_view.cpp | 2 | ||||
-rw-r--r-- | src/test/fuzz/string.cpp | 10 | ||||
-rw-r--r-- | src/test/getarg_tests.cpp | 6 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 55 | ||||
-rw-r--r-- | src/util/strencodings.h | 19 | ||||
-rw-r--r-- | src/validation.cpp | 2 | ||||
-rw-r--r-- | src/validation.h | 2 |
24 files changed, 135 insertions, 63 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 03328ac42c..e00c68585e 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <httpserver.h> #include <chainparamsbase.h> @@ -597,7 +601,13 @@ CService HTTPRequest::GetPeer() const // evhttp retains ownership over returned address string const char* address = ""; uint16_t port = 0; + +#ifdef HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR + evhttp_connection_get_peer(con, &address, &port); +#else evhttp_connection_get_peer(con, (char**)&address, &port); +#endif // HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR + peer = LookupNumeric(address, port); } return peer; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 9f3dd42b56..6a2781079c 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -41,6 +41,7 @@ #endif // ENABLE_WALLET #include <boost/signals2/connection.hpp> +#include <chrono> #include <memory> #include <QApplication> @@ -412,10 +413,10 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { window->message(title, message, style); }); - QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + QTimer::singleShot(100ms, paymentServer, &PaymentServer::uiReady); } #endif - pollShutdownTimer->start(200); + pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY); } else { Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown requestShutdown(); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index d3519edf7f..a28329082a 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -17,6 +17,7 @@ #include <netbase.h> #include <util/system.h> #include <util/threadnames.h> +#include <util/time.h> #include <validation.h> #include <stdint.h> @@ -221,12 +222,12 @@ QString ClientModel::formatClientStartupTime() const QString ClientModel::dataDir() const { - return GUIUtil::boostPathToQString(gArgs.GetDataDirNet()); + return GUIUtil::PathToQString(gArgs.GetDataDirNet()); } QString ClientModel::blocksDir() const { - return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath()); + return GUIUtil::PathToQString(gArgs.GetBlocksDirPath()); } void ClientModel::updateBanlist() @@ -288,7 +289,7 @@ static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_ const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX; const int64_t now = throttle ? GetTimeMillis() : 0; int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; - if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) { + if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) { return; } diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 882d2c8f52..1adcd5b6b9 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -5,10 +5,16 @@ #ifndef BITCOIN_QT_GUICONSTANTS_H #define BITCOIN_QT_GUICONSTANTS_H +#include <chrono> #include <cstdint> -/* Milliseconds between model updates */ -static const int MODEL_UPDATE_DELAY = 250; +using namespace std::chrono_literals; + +/* A delay between model updates */ +static constexpr auto MODEL_UPDATE_DELAY{250ms}; + +/* A delay between shutdown pollings */ +static constexpr auto SHUTDOWN_POLLING_DELAY{200ms}; /* AskPassphraseDialog -- Maximum passphrase length */ static const int MAX_PASSPHRASE_SIZE = 1024; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index f9f0ea81ba..c6c8f7b7a6 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -281,7 +281,7 @@ void LoadFont(const QString& file_name) QString getDefaultDataDirectory() { - return boostPathToQString(GetDefaultDataDir()); + return PathToQString(GetDefaultDataDir()); } QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, @@ -418,7 +418,7 @@ void openDebugLogfile() /* Open debug.log with the associated application */ if (fs::exists(pathDebug)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); + QDesktopServices::openUrl(QUrl::fromLocalFile(PathToQString(pathDebug))); } bool openBitcoinConf() @@ -434,11 +434,11 @@ bool openBitcoinConf() configFile.close(); /* Open bitcoin.conf with the associated application */ - bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(PathToQString(pathConfig))); #ifdef Q_OS_MAC // Workaround for macOS-specific behavior; see #15409. if (!res) { - res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)}); + res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", PathToQString(pathConfig)}); } #endif @@ -652,12 +652,12 @@ void setClipboard(const QString& str) } } -fs::path qstringToBoostPath(const QString &path) +fs::path QStringToPath(const QString &path) { return fs::u8path(path.toStdString()); } -QString boostPathToQString(const fs::path &path) +QString PathToQString(const fs::path &path) { return QString::fromStdString(path.u8string()); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index aaed0ea690..9b25b77325 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -209,10 +209,10 @@ namespace GUIUtil bool SetStartOnSystemStartup(bool fAutoStart); /** Convert QString to OS specific boost path through UTF-8 */ - fs::path qstringToBoostPath(const QString &path); + fs::path QStringToPath(const QString &path); /** Convert OS specific boost path to QString through UTF-8 */ - QString boostPathToQString(const fs::path &path); + QString PathToQString(const fs::path &path); /** Convert enum Network to QString */ QString NetworkToQString(Network net); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index c2d6104658..e9a4034e62 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -67,7 +67,7 @@ FreespaceChecker::FreespaceChecker(Intro *_intro) void FreespaceChecker::check() { QString dataDirStr = intro->getPathToCheck(); - fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr); + fs::path dataDir = GUIUtil::QStringToPath(dataDirStr); uint64_t freeBytesAvailable = 0; int replyStatus = ST_OK; QString replyMessage = tr("A new data directory will be created."); @@ -216,7 +216,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); - if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) + if(!fs::exists(GUIUtil::QStringToPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) { /* Use selectParams here to guarantee Params() can be used by node interface */ try { @@ -240,9 +240,9 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) } dataDir = intro.getDataDirectory(); try { - if (TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir))) { + if (TryCreateDirectories(GUIUtil::QStringToPath(dataDir))) { // If a new data directory has been created, make wallets subdirectory too - TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets"); + TryCreateDirectories(GUIUtil::QStringToPath(dataDir) / "wallets"); } break; } catch (const fs::filesystem_error&) { @@ -263,7 +263,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) * (to be consistent with bitcoind behavior) */ if(dataDir != GUIUtil::getDefaultDataDirectory()) { - gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::qstringToBoostPath(dataDir))); // use OS locale for path setting + gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::QStringToPath(dataDir))); // use OS locale for path setting } return true; } diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 177f45cb7b..c05571677c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -19,6 +19,8 @@ #include <netbase.h> #include <txdb.h> // for -dbcache defaults +#include <chrono> + #include <QDataWidgetMapper> #include <QDir> #include <QIntValidator> @@ -362,7 +364,7 @@ void OptionsDialog::showRestartWarning(bool fPersistent) ui->statusLabel->setText(tr("This change would require a client restart.")); // clear non-persistent status label after 10 seconds // Todo: should perhaps be a class attribute, if we extend the use of statusLabel - QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel); + QTimer::singleShot(10s, this, &OptionsDialog::clearStatusLabel); } } diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index e0219084b7..5d9ed5bf23 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -209,8 +209,8 @@ static void CopySettings(QSettings& dst, const QSettings& src) /** Back up a QSettings to an ini-formatted file. */ static void BackupSettings(const fs::path& filename, const QSettings& src) { - qInfo() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename); - QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat); + qInfo() << "Backing up GUI settings to" << GUIUtil::PathToQString(filename); + QSettings dst(GUIUtil::PathToQString(filename), QSettings::IniFormat); dst.clear(); CopySettings(dst, src); } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 0cf311a360..cb09035b45 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -51,7 +51,7 @@ static QString ipcServerName() // Append a simple hash of the datadir // Note that gArgs.GetDataDirNet() returns a different path // for -testnet versus main net - QString ddir(GUIUtil::boostPathToQString(gArgs.GetDataDirNet())); + QString ddir(GUIUtil::PathToQString(gArgs.GetDataDirNet())); name.append(QString::number(qHash(ddir))); return name; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3f806ece1a..50436a46d8 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -24,11 +24,12 @@ #include <node/ui_interface.h> #include <policy/fees.h> #include <txmempool.h> +#include <validation.h> #include <wallet/coincontrol.h> #include <wallet/fees.h> #include <wallet/wallet.h> -#include <validation.h> +#include <chrono> #include <QFontMetrics> #include <QScrollBar> @@ -1063,7 +1064,7 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri int SendConfirmationDialog::exec() { updateButtons(); - countDownTimer.start(1000); + countDownTimer.start(1s); return QMessageBox::exec(); } diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 01ce6a9f30..66637a5dcf 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -20,6 +20,8 @@ #include <wallet/wallet.h> #include <walletinitinterface.h> +#include <chrono> + #include <QApplication> #include <QTimer> #include <QMessageBox> @@ -47,7 +49,7 @@ void EditAddressAndSubmit( dialog->findChild<QLineEdit*>("labelEdit")->setText(label); dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address); - ConfirmMessage(&warning_text, 5); + ConfirmMessage(&warning_text, 5ms); dialog->accept(); QCOMPARE(warning_text, expected_msg); } diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp index 987d921f03..635dbcd1c5 100644 --- a/src/qt/test/util.cpp +++ b/src/qt/test/util.cpp @@ -2,6 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chrono> + #include <QApplication> #include <QMessageBox> #include <QPushButton> @@ -9,7 +11,7 @@ #include <QTimer> #include <QWidget> -void ConfirmMessage(QString* text, int msec) +void ConfirmMessage(QString* text, std::chrono::milliseconds msec) { QTimer::singleShot(msec, [text]() { for (QWidget* widget : QApplication::topLevelWidgets()) { diff --git a/src/qt/test/util.h b/src/qt/test/util.h index df5931a032..f50a6b6c61 100644 --- a/src/qt/test/util.h +++ b/src/qt/test/util.h @@ -5,7 +5,11 @@ #ifndef BITCOIN_QT_TEST_UTIL_H #define BITCOIN_QT_TEST_UTIL_H -#include <QString> +#include <chrono> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE /** * Press "Ok" button in message box dialog. @@ -13,6 +17,6 @@ * @param text - Optionally store dialog text. * @param msec - Number of milliseconds to pause before triggering the callback. */ -void ConfirmMessage(QString* text = nullptr, int msec = 0); +void ConfirmMessage(QString* text, std::chrono::milliseconds msec); #endif // BITCOIN_QT_TEST_UTIL_H diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 95367d6cce..6ab534764b 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -26,6 +26,7 @@ #include <qt/recentrequeststablemodel.h> #include <qt/receiverequestdialog.h> +#include <chrono> #include <memory> #include <QAbstractButton> @@ -121,7 +122,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st if (expectError.empty()) { ConfirmSend(&text, cancel); } else { - ConfirmMessage(&text); + ConfirmMessage(&text, 0ms); } action->trigger(); QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 6f6e40fcf7..1ab1333b72 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -19,6 +19,7 @@ #include <node/ui_interface.h> +#include <chrono> #include <optional> #include <QApplication> @@ -114,8 +115,8 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa amountWidget->setValidator(amountValidator); hlayout->addWidget(amountWidget); - // Delay before filtering transactions in ms - static const int input_filter_delay = 200; + // Delay before filtering transactions + static constexpr auto input_filter_delay{200ms}; QTimer* amount_typing_delay = new QTimer(this); amount_typing_delay->setSingleShot(true); diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 485de2790d..b025bb367c 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -20,6 +20,7 @@ #include <wallet/wallet.h> #include <algorithm> +#include <chrono> #include <QApplication> #include <QMessageBox> @@ -259,12 +260,12 @@ void CreateWalletActivity::createWallet() flags |= WALLET_FLAG_EXTERNAL_SIGNER; } - QTimer::singleShot(500, worker(), [this, name, flags] { + QTimer::singleShot(500ms, worker(), [this, name, flags] { std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message); if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); - QTimer::singleShot(500, this, &CreateWalletActivity::finish); + QTimer::singleShot(500ms, this, &CreateWalletActivity::finish); }); } diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 5b85ccff83..994b4b9e49 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -273,7 +273,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED}; bool expected_code_path = false; try { - (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_setup->m_node.chainman->m_blockman)), stats); + (void)GetUTXOStats(&coins_view_cache, g_setup->m_node.chainman->m_blockman, stats); } catch (const std::logic_error&) { expected_code_path = true; } diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index ab646c68fc..8f071b71fe 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -276,20 +276,14 @@ FUZZ_TARGET(string) } { - const int atoi_result = atoi(random_string_1.c_str()); const int locale_independent_atoi_result = LocaleIndependentAtoi<int>(random_string_1); const int64_t atoi64_result = atoi64_legacy(random_string_1); - const bool out_of_range = atoi64_result < std::numeric_limits<int>::min() || atoi64_result > std::numeric_limits<int>::max(); - if (out_of_range) { - assert(locale_independent_atoi_result == 0); - } else { - assert(atoi_result == locale_independent_atoi_result); - } + assert(locale_independent_atoi_result == std::clamp<int64_t>(atoi64_result, std::numeric_limits<int>::min(), std::numeric_limits<int>::max())); } { const int64_t atoi64_result = atoi64_legacy(random_string_1); const int64_t locale_independent_atoi_result = LocaleIndependentAtoi<int64_t>(random_string_1); - assert(atoi64_result == locale_independent_atoi_result || locale_independent_atoi_result == 0); + assert(atoi64_result == locale_independent_atoi_result); } } diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 88ce9648bc..d5142c8d74 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -6,6 +6,7 @@ #include <util/strencodings.h> #include <util/system.h> +#include <limits> #include <string> #include <utility> #include <vector> @@ -144,6 +145,11 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 0); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); + // Check under-/overflow behavior. + ResetArgs("-foo=-9223372036854775809 -bar=9223372036854775808"); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), std::numeric_limits<int64_t>::min()); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 0), std::numeric_limits<int64_t>::max()); + ResetArgs("-foo=11 -bar=12"); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 11); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 12); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 04c4524911..20d27a237d 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -24,6 +24,8 @@ #include <array> #include <optional> +#include <limits> +#include <map> #include <stdint.h> #include <string.h> #include <thread> @@ -1621,6 +1623,11 @@ BOOST_AUTO_TEST_CASE(test_ToIntegral) BOOST_CHECK(!ToIntegral<uint8_t>("256")); } +int64_t atoi64_legacy(const std::string& str) +{ + return strtoll(str.c_str(), nullptr, 10); +} + BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi) { BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1234"), 1'234); @@ -1648,48 +1655,68 @@ BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi) BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(""), 0); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("aap"), 0); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("0x1"), 0); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-32482348723847471234"), 0); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("32482348723847471234"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-32482348723847471234"), -2'147'483'647 - 1); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("32482348723847471234"), 2'147'483'647); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775809"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775809"), -9'223'372'036'854'775'807LL - 1LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775808"), -9'223'372'036'854'775'807LL - 1LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775807"), 9'223'372'036'854'775'807); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775808"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775808"), 9'223'372'036'854'775'807); + + std::map<std::string, int64_t> atoi64_test_pairs = { + {"-9223372036854775809", std::numeric_limits<int64_t>::min()}, + {"-9223372036854775808", -9'223'372'036'854'775'807LL - 1LL}, + {"9223372036854775807", 9'223'372'036'854'775'807}, + {"9223372036854775808", std::numeric_limits<int64_t>::max()}, + {"+-", 0}, + {"0x1", 0}, + {"ox1", 0}, + {"", 0}, + }; + + for (const auto& pair : atoi64_test_pairs) { + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>(pair.first), pair.second); + } + + // Ensure legacy compatibility with previous versions of Bitcoin Core's atoi64 + for (const auto& pair : atoi64_test_pairs) { + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>(pair.first), atoi64_legacy(pair.first)); + } BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551615"), 18'446'744'073'709'551'615ULL); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551616"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551616"), 18'446'744'073'709'551'615ULL); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483649"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483649"), -2'147'483'648LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483648"), -2'147'483'648LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483647"), 2'147'483'647); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483648"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483648"), 2'147'483'647); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967295"), 4'294'967'295U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967296"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967296"), 4'294'967'295U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32769"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32769"), -32'768); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32768"), -32'768); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32767"), 32'767); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32768"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32768"), 32'767); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65535"), 65'535U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65536"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65536"), 65'535U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-129"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-129"), -128); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-128"), -128); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("127"), 127); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("128"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("128"), 127); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("255"), 255U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 255U); } BOOST_AUTO_TEST_CASE(test_ParseInt64) diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 0945556b5e..1f83fa3ffa 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -16,6 +16,7 @@ #include <charconv> #include <cstdint> #include <iterator> +#include <limits> #include <optional> #include <string> #include <vector> @@ -93,8 +94,12 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut); // New code should use ToIntegral or the ParseInt* functions // which provide parse error feedback. // -// The goal of LocaleIndependentAtoi is to replicate the exact defined behaviour -// of atoi and atoi64 as they behave under the "C" locale. +// The goal of LocaleIndependentAtoi is to replicate the defined behaviour of +// std::atoi as it behaves under the "C" locale, and remove some undefined +// behavior. If the parsed value is bigger than the integer type's maximum +// value, or smaller than the integer type's minimum value, std::atoi has +// undefined behavior, while this function returns the maximum or minimum +// values, respectively. template <typename T> T LocaleIndependentAtoi(const std::string& str) { @@ -109,7 +114,15 @@ T LocaleIndependentAtoi(const std::string& str) s = s.substr(1); } auto [_, error_condition] = std::from_chars(s.data(), s.data() + s.size(), result); - if (error_condition != std::errc{}) { + if (error_condition == std::errc::result_out_of_range) { + if (s.length() >= 1 && s[0] == '-') { + // Saturate underflow, per strtoll's behavior. + return std::numeric_limits<T>::min(); + } else { + // Saturate overflow, per strtoll's behavior. + return std::numeric_limits<T>::max(); + } + } else if (error_condition != std::errc{}) { return 0; } return result; diff --git a/src/validation.cpp b/src/validation.cpp index 47b931a920..5deb44699a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4873,7 +4873,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // about the snapshot_chainstate. CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB()); - if (!GetUTXOStats(snapshot_coinsdb, WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, breakpoint_fnc)) { + if (!GetUTXOStats(snapshot_coinsdb, m_blockman, stats, breakpoint_fnc)) { LogPrintf("[snapshot] failed to generate coins stats\n"); return false; } diff --git a/src/validation.h b/src/validation.h index fdc4e73b0a..edbd68f783 100644 --- a/src/validation.h +++ b/src/validation.h @@ -828,7 +828,7 @@ public: std::thread m_load_block; //! A single BlockManager instance is shared across each constructed //! chainstate to avoid duplicating block metadata. - node::BlockManager m_blockman GUARDED_BY(::cs_main); + node::BlockManager m_blockman; /** * In order to efficiently track invalidity of headers, we keep the set of |