From f3a612f9016fe1f59c73d6059274bea8025b8940 Mon Sep 17 00:00:00 2001 From: furszy Date: Wed, 28 Feb 2024 09:47:20 -0300 Subject: gui: guard accessing a nullptr 'clientModel' During shutdown, already queue events dispatched from the backend such 'numConnectionsChanged' and 'networkActiveChanged' could try to access the clientModel object, which might not exist because we manually delete it inside 'BitcoinApplication::requestShutdown()'. --- src/qt/bitcoin.cpp | 5 +++++ src/qt/bitcoingui.cpp | 1 + src/qt/clientmodel.cpp | 7 ++++++- src/qt/clientmodel.h | 2 ++ src/qt/rpcconsole.cpp | 1 + 5 files changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 33c305f0d4..b1a8461d02 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -372,6 +372,11 @@ void BitcoinApplication::requestShutdown() // Request node shutdown, which can interrupt long operations, like // rescanning a wallet. node().startShutdown(); + // Prior to unsetting the client model, stop listening backend signals + if (clientModel) { + clientModel->stop(); + } + // Unsetting the client model can cause the current thread to wait for node // to complete an operation, like wait for a RPC execution to complete. window->setClientModel(nullptr); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index ad80922c8b..5f132b817e 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -989,6 +989,7 @@ void BitcoinGUI::gotoLoadPSBT(bool from_clipboard) void BitcoinGUI::updateNetworkState() { + if (!clientModel) return; int count = clientModel->getNumConnections(); QString icon; switch(count) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index c31e06e88e..bf4172a8bf 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -70,7 +70,7 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO subscribeToCoreSignals(); } -ClientModel::~ClientModel() +void ClientModel::stop() { unsubscribeFromCoreSignals(); @@ -78,6 +78,11 @@ ClientModel::~ClientModel() m_thread->wait(); } +ClientModel::~ClientModel() +{ + stop(); +} + int ClientModel::getNumConnections(unsigned int flags) const { ConnectionDirection connections = ConnectionDirection::None; diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 493e18a07d..68fb2e6322 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -58,6 +58,8 @@ public: explicit ClientModel(interfaces::Node& node, OptionsModel *optionsModel, QObject *parent = nullptr); ~ClientModel(); + void stop(); + interfaces::Node& node() const { return m_node; } OptionsModel *getOptionsModel(); PeerTableModel *getPeerTableModel(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4ef45490d9..d2b184ebdf 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -966,6 +966,7 @@ void RPCConsole::message(int category, const QString &message, bool html) void RPCConsole::updateNetworkState() { + if (!clientModel) return; QString connections = QString::number(clientModel->getNumConnections()) + " ("; connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / "; connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")"; -- cgit v1.2.3