Skip to content

Commit e43ce25

Browse files
committed
Merge bitcoin-core/gui#835: Fix crash when closing wallet
a965f2b gui: fix crash when closing wallet (furszy) Pull request description: The crash occurs because `WalletController::removeAndDeleteWallet` is called twice for the same wallet model: first in the GUI's button connected function `WalletController::closeWallet`, and then again when the backend emits the `WalletModel::unload` signal. This causes the issue because `removeAndDeleteWallet` inlines an `erase(std::remove())`. So, if `std::remove` returns an iterator to the end (indicating the element wasn't found because it was already erased), the subsequent call to `erase` leads to an undefined behavior. Test Notes: Try closing any wallet using the toolbar button in the GUI. It will crash in master, but not here. Fixes bitcoin#30887. ACKs for top commit: pablomartin4btc: tACK a965f2b jarolrod: ACK a965f2b hebasto: ACK a965f2b. Tree-SHA512: c94681b95cb566f7aabd0d4fb10f797c2cea6ac569abc265e918f08e6abae3335432a0b0879372b54b2c109798ed0a4a249bf162c34add59cbd18d38a2d9660e
2 parents cf0120f + a965f2b commit e43ce25

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

src/qt/walletcontroller.cpp

+10-8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ std::map<std::string, std::pair<bool, std::string>> WalletController::listWallet
7979
return wallets;
8080
}
8181

82+
void WalletController::removeWallet(WalletModel* wallet_model)
83+
{
84+
// Once the wallet is successfully removed from the node, the model will emit the 'WalletModel::unload' signal.
85+
// This signal is already connected and will complete the removal of the view from the GUI.
86+
// Look at 'WalletController::getOrCreateWallet' for the signal connection.
87+
wallet_model->wallet().remove();
88+
}
89+
8290
void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent)
8391
{
8492
QMessageBox box(parent);
@@ -89,10 +97,7 @@ void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent)
8997
box.setDefaultButton(QMessageBox::Yes);
9098
if (box.exec() != QMessageBox::Yes) return;
9199

92-
// First remove wallet from node.
93-
wallet_model->wallet().remove();
94-
// Now release the model.
95-
removeAndDeleteWallet(wallet_model);
100+
removeWallet(wallet_model);
96101
}
97102

98103
void WalletController::closeAllWallets(QWidget* parent)
@@ -105,11 +110,8 @@ void WalletController::closeAllWallets(QWidget* parent)
105110

106111
QMutexLocker locker(&m_mutex);
107112
for (WalletModel* wallet_model : m_wallets) {
108-
wallet_model->wallet().remove();
109-
Q_EMIT walletRemoved(wallet_model);
110-
delete wallet_model;
113+
removeWallet(wallet_model);
111114
}
112-
m_wallets.clear();
113115
}
114116

115117
WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)

src/qt/walletcontroller.h

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ class WalletController : public QObject
8585

8686
friend class WalletControllerActivity;
8787
friend class MigrateWalletActivity;
88+
89+
//! Starts the wallet closure procedure
90+
void removeWallet(WalletModel* wallet_model);
8891
};
8992

9093
class WalletControllerActivity : public QObject

0 commit comments

Comments
 (0)