Skip to content

Commit

Permalink
gui: fix crash when closing wallet
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
furszy committed Sep 12, 2024
1 parent cf0120f commit a965f2b
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
18 changes: 10 additions & 8 deletions src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ std::map<std::string, std::pair<bool, std::string>> WalletController::listWallet
return wallets;
}

void WalletController::removeWallet(WalletModel* wallet_model)
{
// Once the wallet is successfully removed from the node, the model will emit the 'WalletModel::unload' signal.
// This signal is already connected and will complete the removal of the view from the GUI.
// Look at 'WalletController::getOrCreateWallet' for the signal connection.
wallet_model->wallet().remove();
}

void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent)
{
QMessageBox box(parent);
Expand All @@ -89,10 +97,7 @@ void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent)
box.setDefaultButton(QMessageBox::Yes);
if (box.exec() != QMessageBox::Yes) return;

// First remove wallet from node.
wallet_model->wallet().remove();
// Now release the model.
removeAndDeleteWallet(wallet_model);
removeWallet(wallet_model);
}

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

QMutexLocker locker(&m_mutex);
for (WalletModel* wallet_model : m_wallets) {
wallet_model->wallet().remove();
Q_EMIT walletRemoved(wallet_model);
delete wallet_model;
removeWallet(wallet_model);
}
m_wallets.clear();
}

WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)
Expand Down
3 changes: 3 additions & 0 deletions src/qt/walletcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ class WalletController : public QObject

friend class WalletControllerActivity;
friend class MigrateWalletActivity;

//! Starts the wallet closure procedure
void removeWallet(WalletModel* wallet_model);
};

class WalletControllerActivity : public QObject
Expand Down

0 comments on commit a965f2b

Please sign in to comment.