-
Notifications
You must be signed in to change notification settings - Fork 312
Fix segfault when shutdown during wallet open #693
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
Fix segfault when shutdown during wallet open #693
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. |
fcbbc96
to
114d738
Compare
Pushed an update to address the failing tests. They failed because the gui/src/qt/transactiontablemodel.cpp Lines 73 to 76 in d8bdee0
The reason given is The The fix for that is either to change the connection in the I chose the latter method. |
QMetaObject::invokeMethod(ui->scrollArea, [this] { | ||
if (ui->scrollArea->verticalScrollBar()) { | ||
ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->maximum()); | ||
} | ||
}, Qt::QueuedConnection); |
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.
This is most likely because we are creating the widget in a separate thread.
Try this:
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
--- a/src/qt/sendcoinsdialog.cpp (revision 114d738830368dc155f27a72128adf91b4fffd37)
+++ b/src/qt/sendcoinsdialog.cpp (date 1672923728012)
@@ -600,11 +600,9 @@
entry->clear();
entry->setFocus();
ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
- QMetaObject::invokeMethod(ui->scrollArea, [this] {
- if (ui->scrollArea->verticalScrollBar()) {
- ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->maximum());
- }
- }, Qt::QueuedConnection);
+ if (ui->scrollArea->verticalScrollBar()) {
+ ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->maximum());
+ }
updateTabsAndLabels();
return entry;
@@ -697,6 +695,13 @@
return true;
}
+void SendCoinsDialog::showEvent(QShowEvent* event)
+{
+ if (ui->scrollArea->verticalScrollBar()) {
+ ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->maximum());
+ }
+}
+
void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances)
{
if(model && model->getOptionsModel())
Index: src/qt/sendcoinsdialog.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
--- a/src/qt/sendcoinsdialog.h (revision 114d738830368dc155f27a72128adf91b4fffd37)
+++ b/src/qt/sendcoinsdialog.h (date 1672923728023)
@@ -49,6 +49,8 @@
void pasteEntry(const SendCoinsRecipient &rv);
bool handlePaymentRequest(const SendCoinsRecipient &recipient);
+ void showEvent(QShowEvent* event) override;
+
public Q_SLOTS:
void clear();
void reject() override;
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.
Thank you for the suggestion!
While this (also) fixes the first segfault, it doesn't achieve the intended scrolling behavior (at least on my macOS setup).
Before clicking 'Add Recipient':
After:
Whereas the original workaround (and my workaround of the workaround) gives this "After":
It seems to be a fairly common issue without an ideal solution. There are more involved solutions, like subscribing to rangeChanged
signals, but those would require much more logic (eg - ignore those when manually resizing the viewport, etc.).
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.
hmm true, ok. Sounds good to go with the simplest fix here.
Would be good to add a comment above so we don't forget the rationale behind it.
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.
Good call. Adding.
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 ACK 114d738 with the nuance of not being able to reproduce the crash on master on my system.
Thanks for the added comment. |
If you open a wallet and send a shutdown signal during that process, the GUI will segfault due to some queued wallet events happening after the wallet controller is deleted. This is a minimal fix for those issues.
11f0202
to
9a1d73f
Compare
cc @promag |
Concept ACK. |
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.
ACK 9a1d73f, I have reviewed the code and it looks OK.
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.
ACK 9a1d73f
Fixes #689
Summary
If you open a wallet and send a shutdown signal during that process, you'll get a segfault when the wallet finishes opening. That's because the
WalletController
object gets deleted manually in bitcoin.cpp during shutdown, but copies of the pointer (and pointers to child objects) are dangling in various places and are accessed in queued events after the deletion.Details
The issue in #689 is caused by the following sequence of events:
finish
signals are sent.finish
signals,qApp->processEvents()
is called, which causes the main event loop to detect the shutdown (now that the modal window has been dismissed). TheWalletController
and all theWalletModel
s are deleted.finish
method, which eventually tries to send a signal from a wallet model, but it's been deleted already (and the signal is sent from a now-dangling pointer).The simplest fix for that is to change the
qApp->processEvents()
into aQueuedConnection
call. (The `qApp->processEvents() was a workaround to get the GUI to scroll to the last item in a list that just got added, and this is just a safer way of doing that).However, once that segfault is fixed, another segfault occurs due to some queued wallet events happening after the wallet controller object is deleted here:
gui/src/qt/bitcoin.cpp
Lines 394 to 401 in 65de8ee
Since
m_wallet_controller
is a copy of that pointer inbitcoingui.cpp
, it's now dangling andif(null)
checks won't work correctly. For instance, this line:gui/src/qt/bitcoingui.cpp
Line 413 in 65de8ee
sets up a
QueuedConnection
tosetCurrentWallet
, but by the time control reaches that method (one event cycle after shutdown deletedm_wallet_controller
inbitcoin.cpp
), the underlying objects have been destroyed (but the pointers are still dangling).Ideally, we'd use a
QPointer
orstd::shared_ptr / std::weak_ptr
s for these, but the changes would be more involved.This is a minimal fix for the issues. Just set
m_wallet_controller
tonullptr
inbitcoingui.cpp
, check its value in a couple places, and avoid a use ofqApp->processEvents
.