-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: Fix unique_ptr usage in boost::signals2 #16963
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wallet: Fix unique_ptr usage in boost::signals2 #16963
Conversation
@ryanofsky maybe you have a better approach? |
Good catch! But why exactly is the fix in #16955 incorrect? It seems like a reasonable workaround to me as long as the wallet still shows up in the GUI (which I would expect if This clone fix should work now, and is more elegant than the nullptr workaround, but wouldn't work great with #10102 unless I changed it to use shared_ptrs internally or complicate lifetime management some other way to support cloning. More ideally, I would delete chain.loadWallet(interfaces::MakeWallet(walletInstance)); with for (auto& load_wallet : load_wallet_fns) {
load_wallet(interfaces::MakeWallet(walletInstance));
} But I'm ok with the nullptr fix or the clone fix or however you want to proceed here. |
IMO it's incorrect because it doesn't remove the invalid |
There's nothing guaranteeing it (I think?) |
Related discussion #15288 (comment). |
I started playing around with this change (7162be2). Using the same approach as in #16937 I was able to (only once so far) end up with the same wallet loaded twice: Multiple times I've seen (lldb) run
Process 20318 launched: '/Users/michael/github/bitcoin/src/qt/bitcoin-qt' (x86_64)
2019-09-26 20:14:33.701294+0800 bitcoin-qt[20318:1442147] MessageTracer: Falling back to default whitelist
Process 20318 stopped
* thread #1, name = 'bitcoin-main', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
frame #0: 0x000000010009182e bitcoin-qt`GUIUtil::TableViewLastColumnResizingFixer::disconnectViewHeadersSignals(this=0x0000000000000000) at guiutil.cpp:445:16
442 // We need to disconnect these while handling the resize events, otherwise we can enter infinite loops.
443 void TableViewLastColumnResizingFixer::disconnectViewHeadersSignals()
444 {
-> 445 disconnect(tableView->horizontalHeader(), &QHeaderView::sectionResized, this, &TableViewLastColumnResizingFixer::on_sectionResized);
446 disconnect(tableView->horizontalHeader(), &QHeaderView::geometriesChanged, this, &TableViewLastColumnResizingFixer::on_geometriesChanged);
447 }
448
Target 0: (bitcoin-qt) stopped. Ran out of time tonight, so will keep looking tomorrow. |
Thanks @fanquake!
Very strange, I wonder if the "big" wallet has 2 Edit: problem: 2 calls to Lines 623 to 627 in 6288f15
and if the dynamic loading happens after L623 and before L627. |
@fanquake that happens due to |
That was happening with just the |
Going to |
4066030
to
52b9d00
Compare
re: #16963 (comment)
I haven't seen any response to this suggestion, so I pushed a quick untested implementation to master...ryanofsky:pr/loadwallets I think it would be a better solution than trying to clone interfaces because cloning interfaces can't work when an implementation owns noncopyable resources. I also don't agree a bug was introduced in the commit noted #16963 (comment) or see how #16955 is buggy or would be a bad workaround if documented appropriately. Anyway, these are just opinions I'm giving since I was tagged earlier #16963 (comment). I don't feel strongly, and trust @promag's judgement on what solution to use since he's taking the initiative here. |
I think calling a refactor a fix is strange (a refactor ,by definition, doesn't change behavior): what is this, a refactor or a bug fix? |
@ryanofsky sorry for not replying, I'll take a look. @laanwj yeah in that case a fix. |
It's a workaround due to bad usage of std::unique_ptr and boost::signals2. I think a fix is preferable.
What you mean? can you reproduce #16937 before 1106a6f?
Sweet! 5d7a233 LGTM, picked and reworded. |
40b4d25
to
fce3b88
Compare
Fixed disable wallet builds and squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK fce3b88, but I wrote some code in this, so discount my review a bit.
The slot BitcoinGUI::addWallet can be invoked twice for the same WalletModel due to a concurrent wallet being loaded after the first `connect()`: ```cpp connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { addWallet(wallet_model); ```
e956882
to
6d6a7a8
Compare
@ryanofsky fixed, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Second commit 81ea66c might need more code comments and a better commit description to be more easily reviewable. http://www.erisian.com.au/bitcoin-core-dev/log-2019-11-02.html#l-128
The main thing this change is doing is deleting the The reason for making this change is that the load wallet callback function takes a Another thing that might look complicated here and could be better documented is the new //! Return handler wrapping a cleanup function.
std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup); This just takes a |
And for that reason a |
Github-Pull: bitcoin#16963 Rebased-From: 81ea66c
Github-Pull: bitcoin#16963 Rebased-From: 6d6a7a8 The slot BitcoinGUI::addWallet can be invoked twice for the same WalletModel due to a concurrent wallet being loaded after the first `connect()`: ```cpp connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { addWallet(wallet_model); ```
Github-Pull: bitcoin#16963 Rebased-From: 81ea66c
Github-Pull: bitcoin#16963 Rebased-From: 6d6a7a8 The slot BitcoinGUI::addWallet can be invoked twice for the same WalletModel due to a concurrent wallet being loaded after the first `connect()`: ```cpp connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { addWallet(wallet_model); ```
@@ -48,6 +50,7 @@ bool HasWallets(); | |||
std::vector<std::shared_ptr<CWallet>> GetWallets(); | |||
std::shared_ptr<CWallet> GetWallet(const std::string& name); | |||
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings); | |||
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this HandleLoadWallet
arg could be an r-value reference, on account of the std::move
calling pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 6d6a7a8
@@ -36,7 +36,7 @@ class WalletFrame : public QFrame | |||
|
|||
void setClientModel(ClientModel *clientModel); | |||
|
|||
void addWallet(WalletModel *walletModel); | |||
bool addWallet(WalletModel *walletModel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer a bool ready()
method that simply checks the conditions rather than arbitrarily booling non-bool methods like this. I think it's unnecessarily confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kallewoof thanks for reviewing.
arbitrarily booling non-bool methods like this.
What you mean "like this"? I could refactor by adding bool WalletFrame::hasWallet(WalletModel*) const
but IMO this is also fine, for instance, std::set::insert
also returns whether the item was added.
What it could have is the NODISCARD
attribute, but ATM it's not used in src/qt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it's an anti-pattern to silently fail when an operation is attempted, returning a success bool instead makes sense to me in that case, or alternatively raise on failure and use ready
as you suggest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I know this is done elsewhere (even in std
), but I don't think it's a good idea, personally. It often results in having to look up what exactly is being returned, made even worse with things like bool CreateThing(...)
. (Looking at the signature unless Thing
is a bool type, the return value is most likely the result of the create operation, but seeing it in the wild as auto foo = CreateThing(...)
you won't know if foo is a bool or a Thing
without checking.)
Agree that failing silently is a bad idea. Raising sounds good to me, unless you really like the bool approach, in which case keep it as is.
6d6a7a8 gui: Fix duplicate wallet showing up (João Barbosa) 81ea66c Drop signal CClientUIInterface::LoadWallet (Russell Yanofsky) Pull request description: This PR includes 2 fixes: - prevent GUI LoadWallet handlers from crashing on startup when multiple handlers are attached, because the first handler takes ownership of the wallet unique pointer. Now every handler will receive its own unique pointer; - prevent showing a wallet twice in the GUI on startup due to a race with `loadwallet`. Fixes #16937 ACKs for top commit: fjahr: code review ACK 6d6a7a8 ryanofsky: Code review ACK 6d6a7a8. No changes since last ACK other than rebase due to #17070 kallewoof: Code review ACK 6d6a7a8 Tree-SHA512: 7f0658c9011f81dfa176a094c2263448ee1d14fda7dc94e8b55ee9c8b81538bd2d1e4bf8a8dbfcd029ebfc9feb6d3cda9dee3f911122df0a4b1e0ca75f653ba4
Code review ACK 6d6a7a8. @ryanofsky Thanks for the explanation that was very helpful |
6d6a7a8 gui: Fix duplicate wallet showing up (João Barbosa) 81ea66c Drop signal CClientUIInterface::LoadWallet (Russell Yanofsky) Pull request description: This PR includes 2 fixes: - prevent GUI LoadWallet handlers from crashing on startup when multiple handlers are attached, because the first handler takes ownership of the wallet unique pointer. Now every handler will receive its own unique pointer; - prevent showing a wallet twice in the GUI on startup due to a race with `loadwallet`. Fixes bitcoin#16937 ACKs for top commit: fjahr: code review ACK 6d6a7a8 ryanofsky: Code review ACK 6d6a7a8. No changes since last ACK other than rebase due to bitcoin#17070 kallewoof: Code review ACK 6d6a7a8 Tree-SHA512: 7f0658c9011f81dfa176a094c2263448ee1d14fda7dc94e8b55ee9c8b81538bd2d1e4bf8a8dbfcd029ebfc9feb6d3cda9dee3f911122df0a4b1e0ca75f653ba4
Github-Pull: bitcoin#16963 Rebased-From: 81ea66c
The slot BitcoinGUI::addWallet can be invoked twice for the same WalletModel due to a concurrent wallet being loaded after the first `connect()`: ```cpp connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { addWallet(wallet_model); ``` Github-Pull: bitcoin#16963 Rebased-From: 6d6a7a8
cd67b1d Use correct C++11 header for std::swap() (Hennadii Stepanov) b8101fb Fix comparison function signature (Hennadii Stepanov) eac4907 Don't allow implementers to think ScriptHash(Witness*()) results in nesting computation (Gregory Sanders) e2c45d8 IsUsedDestination shouldn't use key id as script id for ScriptHash (Gregory Sanders) a5489c9 IsUsedDestination should count any known single-key address (Gregory Sanders) 88729d8 Fix issue with conflicted mempool tx in listsinceblock (Adam Jonas) eafcea7 gui: Fix duplicate wallet showing up (João Barbosa) 7e66d04 Drop signal CClientUIInterface::LoadWallet (Russell Yanofsky) 179d55f zmq: Fix due to invalid argument and multiple notifiers (João Barbosa) Pull request description: Backports - #16963 - #17445 - #17258 - #17621 - #17924 - #17634 ACKs for top commit: laanwj: ACK cd67b1d, checked that I got more or less the same result (including conflict resolution) backporting these commits Tree-SHA512: 645786267cfb10a01a56f7cfd91ddead5f1475df5714595ae480237e04d40c5cfb7460b40532279cacd83e4b775a4ace68a258ec2184b8ad0e997a690a9245e5
Summary: * Drop signal CClientUIInterface::LoadWallet * gui: Fix duplicate wallet showing up The slot BitcoinGUI::addWallet can be invoked twice for the same WalletModel due to a concurrent wallet being loaded after the first `connect()`: ```cpp connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet); connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet); for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) { addWallet(wallet_model); ``` This is a backport of Core [[bitcoin/bitcoin#16963 | PR16963]] Because `WalletFrame::addWallet` already returns a bool, that part of the patch wasn't necessary. Test Plan: ninja all check-all Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D7699
6d6a7a8 gui: Fix duplicate wallet showing up (João Barbosa) 81ea66c Drop signal CClientUIInterface::LoadWallet (Russell Yanofsky) Pull request description: This PR includes 2 fixes: - prevent GUI LoadWallet handlers from crashing on startup when multiple handlers are attached, because the first handler takes ownership of the wallet unique pointer. Now every handler will receive its own unique pointer; - prevent showing a wallet twice in the GUI on startup due to a race with `loadwallet`. Fixes bitcoin#16937 ACKs for top commit: fjahr: code review ACK 6d6a7a8 ryanofsky: Code review ACK 6d6a7a8. No changes since last ACK other than rebase due to bitcoin#17070 kallewoof: Code review ACK 6d6a7a8 Tree-SHA512: 7f0658c9011f81dfa176a094c2263448ee1d14fda7dc94e8b55ee9c8b81538bd2d1e4bf8a8dbfcd029ebfc9feb6d3cda9dee3f911122df0a4b1e0ca75f653ba4
Summary: This is a backport of Core [[bitcoin/bitcoin#15464 | PR15464]] `addWallet` is not modified because the return value is added back and used in [[bitcoin/bitcoin#16963 | PR16963]] which was backported in D7699. Test Plan: `ninja && src/qt/bitcoin-qt` Reviewers: #bitcoin_abc, majcosta Reviewed By: #bitcoin_abc, majcosta Differential Revision: https://reviews.bitcoinabc.org/D8363
This PR includes 2 fixes:
prevent GUI LoadWallet handlers from crashing on startup when multiple handlers are attached, because the first handler takes ownership of the wallet unique pointer. Now every handler will receive its own unique pointer;
prevent showing a wallet twice in the GUI on startup due to a race with
loadwallet
.Fixes #16937