-
Notifications
You must be signed in to change notification settings - Fork 312
Handle exceptions instead of crash #260
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
Conversation
|
dee52c2
to
63cca51
Compare
Note to reviewersTo test this PR you could:
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2674,7 +2674,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256&
}
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
int64_t block_time;
- CHECK_NONFATAL(chain.findBlock(block_hash, FoundBlock().time(block_time)));
+ CHECK_NONFATAL(!chain.findBlock(block_hash, FoundBlock().time(block_time)));
if (block_time < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
return false;
} and initiate a new transaction creation, or
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -330,7 +330,7 @@ public:
}
num_blocks = m_wallet->GetLastBlockHeight();
block_time = -1;
- CHECK_NONFATAL(m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time)));
+ CHECK_NONFATAL(!m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time)));
tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
return true;
} and initiate opening a wallet. |
@ryanofsky
The idea is to distinguish non-fatal errors when no need to stop the client; described by @MarcoFalke:
Also, from Developer Notes:
|
@promag @ryanofsky @jonasschnelli Kindly asking for reviewing :) 🐅 |
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.
Tested ACK 63cca51 on Ubuntu 20.04 Qt Qt 5.12.8.
The exception was also displayed on terminal:
************************
EXCEPTION: 18NonFatalCheckError
wallet/wallet.cpp:2678 (IsCurrentForAntiFeeSniping)
Internal bug detected: '!chain.findBlock(block_hash, FoundBlock().time(block_time))'
You may report this issue here: https://github.com/bitcoin/bitcoin/issues
bitcoin in QPushButton->SendCoinsDialog
Personally I like the "A fatal error occured. Bitcoin Core can no longer …" message with a seperator and then the detailed error message much better than an "Internal error" popup with some developer text. I think we should keep that.
Is it logged to the debug log? Anything printed to stderr tends to get lost (or is logged to a really hard to find place) on graphical operating systems. |
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 63cca51. Agree with laanwj that error text could be improved and I made a specific suggestion below, but this is already better than crashing, and I like the approach of catching exceptions in the connect handler so they don't cause problems for Qt.
re: #260 (comment)
Yep, PrintExceptionContinue logs it. |
Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
This helper function will be used in the following commits. Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
Throwing an exception from a slot invoked by Qt's signal-slot connection mechanism is considered undefined behavior, unless it is handled within the slot. The GUIUtil::ExceptionSafeConnect function should be used for exception handling within slots.
@@ -65,7 +65,8 @@ WalletModel::~WalletModel() | |||
void WalletModel::startPollBalance() | |||
{ | |||
// This timer will be fired repeatedly to update the balance | |||
connect(timer, &QTimer::timeout, this, &WalletModel::pollBalanceChanged); | |||
connect(timer, &QTimer::timeout, this, &WalletModel::timerTimeout); |
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.
Might want to add a comment here why the signal is not directly connected (e.g. because QTimer::timeout
is a private signal)
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.
Thanks! Updated.
Actually, the private QTimer::timeout signal has one QTimer::QPrivateSignal parameter.
Also the parameter list of the TransactionView::bumpFee slot is made compatible with one of the QAction::triggered signal.
Also, uic automatic connection replaced with an explicit one.
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 b8e5d0d. This is great! I think more improvements are possible but implementation is very clean and I love how targeted each commit is. Changes since last review: adding more explanatory text, making links clickable, reorganizing.
QMessageBox::critical( | ||
nullptr, tr("Runaway exception"), | ||
tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) % | ||
QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); |
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.
In commit "qt: Make PACKAGE_BUGREPORT link clickable" (af7e365)
Since our project only uses the issue tracker for development, not user support, it would be good in the future to link to something like stack exchange or a support resources page if a fatal error occurs, instead of the issue tracker.
But this commit is only making existing issue tracker links clickable, not adding new links, so it doesn't cause problems and is good because it keeps the links rendered in consistent way.
In the future it might be be good stop having "Runaway exception" dialogs and instead have distinct "Internal bug" (e.g. unhandled preconditions or postconditions) and "Fatal error" (e.g. failing disk writes) dialogs, treating the first kind like bugs and the second kind like support issues. But it seems good to keep the scope of this PR narrow and focused on the nonfatal checks like it is now.
const QObject* sender, | ||
const QObject* receiver) | ||
{ | ||
std::string description = sender->metaObject()->className(); |
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.
In commit "qt: Add GUIUtil::ExceptionSafeConnect function" (f7e260a)
Not important, but just in case you revisit this, I think it might be a little clearer to call this variable "location" instead of "description". (I was a little confused at first about why it didn't seem to include information from the exception.)
Do you mind looking into this PR as it resolves your bitcoin/bitcoin#18643? |
Code review ACK b8e5d0d |
This PR is an alternative to bitcoin/bitcoin#18897, and is based on Russ' idea:
Related issues
Qt docs: https://doc.qt.io/qt-5.12/exceptionsafety.html#exceptions-in-client-code
With this PR the GUI handles the wallet-related exception, and:
stderr
:debug.log