Skip to content
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

qt: Handle exceptions instead of crash #18897

Closed
wants to merge 3 commits into from

Conversation

hebasto
Copy link
Member

@hebasto hebasto commented May 6, 2020

Related issue #18643.

With this PR the GUI handles the wallet-related exception, displays it to a user:

Screenshot from 2020-05-06 18-16-51

and, if the exception is a non-fatal error, leaves the main window running.

@DrahtBot
Copy link
Contributor

DrahtBot commented May 6, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@maflcko
Copy link
Member

maflcko commented May 6, 2020

Do I understand correctly that every gui element needs to have this handler if a crash wants to be avoided?

I.e. every dialog or window that could possibly pop up and just putting this catch in the "main gui" won't work?

@maflcko
Copy link
Member

maflcko commented May 6, 2020

Concept ACK either way

@hebasto
Copy link
Member Author

hebasto commented May 6, 2020

Do I understand correctly that every gui element needs to have this handler if a crash wants to be avoided?

I.e. every dialog or window that could possibly pop up and just putting this catch in the "main gui" won't work?

Every slot.

See: https://doc.qt.io/qt-5/exceptionsafety.html#signals-and-slots

@maflcko
Copy link
Member

maflcko commented May 6, 2020

So currently it is undefined behaviour. Wow, qt is scary.

Slightly stronger concept ACK, but this also makes we want to remove qt.

@hebasto
Copy link
Member Author

hebasto commented May 6, 2020

So currently it is undefined behaviour. Wow, qt is scary.

Slightly stronger concept ACK, but this also makes we want to remove qt.

Unrelated, but do we have a long-term plan of moving from Qt?

src/qt/bitcoingui.cpp Outdated Show resolved Hide resolved
@hebasto
Copy link
Member Author

hebasto commented May 6, 2020

Updated 40a622d -> 44f7f51 (pr18897.01 -> pr18897.02, diff):


The OP and the screenshot have been updated.

@hebasto hebasto changed the title gui: Handle NonFatalCheckError instead of crash gui: Handle exceptions instead of crash May 6, 2020
@hebasto hebasto marked this pull request as draft May 6, 2020 15:34
@ryanofsky
Copy link
Contributor

This looks pretty reasonable, and I'd ack this if not a draft PR.

One thing that might be nice is a generic exception catcher QObject that emits a handleRunawayException signal. This way the signal doesn't need to be declared multiple places and repeated boilerplate for catching exceptions could go away. So something like:

m_exception_catcher->exec([&]{ sendButtonClickedHelper(); });

could replace:

try {
    sendButtonClickedHelper();
} catch (const std::exception& e) {
    Q_EMIT runawayException(QString::fromStdString(e.what()));
} catch (...) {
    Q_EMIT runawayException(QString("Unknown failure occurred."));
}

Copy link
Member

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's this approach:

bool BitcoinApplication::notify(QObject* receiver, QEvent* event)
{
    try {
        return QApplication::notify(receiver, event);
    } catch (const std::exception& ex) {
        // ..
    } catch (...) {
        // ..
    }
    return false;
}

But the documentation says this will be deprecated.

So currently it is undefined behaviour. Wow, qt is scary.

Slightly stronger concept ACK, but this also makes we want to remove qt.

Why? This is by design, Qt doesn't want to handle exceptions, what should it do anyway?

src/qt/sendcoinsdialog.cpp Outdated Show resolved Hide resolved
@hebasto hebasto force-pushed the 200506-slot-ex branch 2 times, most recently from 7c8178b to 24a90d5 Compare May 8, 2020 11:19
@hebasto
Copy link
Member Author

hebasto commented May 8, 2020

@ryanofsky @promag Thank you for your reviews.

Updated 44f7f51 -> 24a90d5 (pr18897.02 -> pr18897.03, diff).

Ready for review now :)

@hebasto hebasto marked this pull request as ready for review May 8, 2020 11:23
@hebasto hebasto changed the title gui: Handle exceptions instead of crash qt: Handle exceptions instead of crash May 8, 2020
src/qt/shieldexception.h Outdated Show resolved Hide resolved
@hebasto
Copy link
Member Author

hebasto commented May 8, 2020

Updated 24a90d5 -> 82529bc (pr18897.03 -> pr18897.04, diff):

Move to src/qt/guiutil.h?

@hebasto
Copy link
Member Author

hebasto commented May 10, 2020

Also #18435 could be related.

@hebasto
Copy link
Member Author

hebasto commented May 11, 2020

Rebased 82529bc -> 1fb68b3 (pr18897.04 -> pr18897.05) due to the conflict with #18914.

src/qt/guiutil.h Outdated Show resolved Hide resolved
@jonasschnelli
Copy link
Contributor

Concept ACK

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 shieldException() function should be used for exception
handling within slots.
@hebasto
Copy link
Member Author

hebasto commented May 13, 2020

Updated 1fb68b3 -> 8f94243 (pr18897.05 -> pr18897.06, diff):

I don't think so, only the main (GUI) thread should deal with widgets.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review ACK 8f94243. This looks very good and much simpler than before!

IMO it would be nice to have a followup PR that eliminated the one-line forwarding methods and just used shieldException directly at the call and signal connect sites. Alternately renaming s/Helper/Unsafe/ would be clearer than status quo. But best to just get rid of the indirections.

bool ok = true;
try {
f();
} catch (const NonFatalCheckError& e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "qt: Add shieldException() function" (553128b)

Would drop this special case for NonFatalCheckError and simply catch std::exception below. NonFatalCheckError is really an internal implementation of the CHECK macro and most useful to unit tests. Exceptions aren't valid in qt callbacks so NonFatalCheckError is no different here than any other exception. Just another unexpected condition that should never happen

PrintExceptionContinue(&e, "Internal error");
ok = QMetaObject::invokeMethod(qApp, "handleNonFatalException", blockingGUIThreadConnection(), Q_ARG(QString, QString::fromStdString(e.what())));
} catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In commit "qt: Add shieldException() function" (553128b)

Here and below would replace "Runaway exception" with "Internal error." No reason to confuse users with implementation details and obscure jargon when it's not providing useful information

@DrahtBot
Copy link
Contributor

🐙 This pull request conflicts with the target branch and needs rebase.

@fanquake
Copy link
Member

Given this only had the 1 ACK (with suggested improvements), and now needs a rebase, lets move this over the GUI repo. I'll move #18643 over there as well.

@fanquake fanquake closed this Sep 15, 2020
@ryanofsky
Copy link
Contributor

lets move this over the GUI repo

Reopening this not to lose track, since it doesn't appear this PR was moved to the GUI repo (or I can't find it). Can close this again if it is actually moved or no longer applicable.

@fanquake
Copy link
Member

@hebasto can you either move this over to the GUI repo, or close and we'll mark it up for grabs? The interested re-opener can open it in the gui repo.

@hebasto
Copy link
Member Author

hebasto commented Mar 26, 2021

@fanquake

@hebasto can you either move this over to the GUI repo, or close and we'll mark it up for grabs? The interested re-opener can open it in the gui repo.

bitcoin-core/gui#260

@hebasto hebasto closed this Mar 26, 2021
laanwj added a commit to bitcoin-core/gui that referenced this pull request Apr 14, 2021
b8e5d0d qt: Handle exceptions in SendCoinsDialog::sendButtonClicked slot (Hennadii Stepanov)
1ac2bc7 qt: Handle exceptions in TransactionView::bumpFee slot (Hennadii Stepanov)
bc00e13 qt: Handle exceptions in WalletModel::pollBalanceChanged slot (Hennadii Stepanov)
eb6156b qt: Handle exceptions in BitcoinGUI::addWallet slot (Hennadii Stepanov)
f7e260a qt: Add GUIUtil::ExceptionSafeConnect function (Hennadii Stepanov)
64a8755 qt: Add BitcoinApplication::handleNonFatalException function (Hennadii Stepanov)
af7e365 qt: Make PACKAGE_BUGREPORT link clickable (Hennadii Stepanov)

Pull request description:

  This PR is an alternative to bitcoin/bitcoin#18897, and is based on Russ' [idea](bitcoin/bitcoin#18897 (review)):
  > IMO it would be nice to have a followup PR that eliminated the one-line forwarding methods ...

  Related issues
  - #91
  - bitcoin/bitcoin#18643

  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:
  - display it to a user:

  ![Screenshot from 2021-04-01 02-55-59](https://user-images.githubusercontent.com/32963518/113226183-33ff8480-9298-11eb-8fe6-2168834ab09a.png)

  - prints a message to `stderr`:
  ```

  ************************
  EXCEPTION: 18NonFatalCheckError
  wallet/wallet.cpp:2677 (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

  ```

  - writes a message to the `debug.log`
  - and, if the exception is a non-fatal error, leaves the main window running.

ACKs for top commit:
  laanwj:
    Code review ACK b8e5d0d
  ryanofsky:
    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.

Tree-SHA512: a9f2a2ee8e64b993b0dbc454edcbc39c68c8852abb5dc1feb58f601c0e0e8014dca81c72733aa3fb07b619c6f49b823ed20c7d79cc92088a3abe040ed2149727
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants