mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
qt: Add GUIUtil::ExceptionSafeConnect function
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.
This commit is contained in:
parent
64a8755af3
commit
f7e260a471
2 changed files with 63 additions and 0 deletions
|
@ -902,4 +902,15 @@ QString MakeHtmlLink(const QString& source, const QString& link)
|
|||
QLatin1String("<a href=\"") % link % QLatin1String("\">") % link % QLatin1String("</a>"));
|
||||
}
|
||||
|
||||
void PrintSlotException(
|
||||
const std::exception* exception,
|
||||
const QObject* sender,
|
||||
const QObject* receiver)
|
||||
{
|
||||
std::string description = sender->metaObject()->className();
|
||||
description += "->";
|
||||
description += receiver->metaObject()->className();
|
||||
PrintExceptionContinue(exception, description.c_str());
|
||||
}
|
||||
|
||||
} // namespace GUIUtil
|
||||
|
|
|
@ -9,18 +9,23 @@
|
|||
#include <fs.h>
|
||||
#include <net.h>
|
||||
#include <netaddress.h>
|
||||
#include <util/check.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QHeaderView>
|
||||
#include <QItemDelegate>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaObject>
|
||||
#include <QObject>
|
||||
#include <QProgressBar>
|
||||
#include <QString>
|
||||
#include <QTableView>
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
class QValidatedLineEdit;
|
||||
class SendCoinsRecipient;
|
||||
|
@ -332,6 +337,53 @@ namespace GUIUtil
|
|||
*/
|
||||
QString MakeHtmlLink(const QString& source, const QString& link);
|
||||
|
||||
void PrintSlotException(
|
||||
const std::exception* exception,
|
||||
const QObject* sender,
|
||||
const QObject* receiver);
|
||||
|
||||
/**
|
||||
* A drop-in replacement of QObject::connect function
|
||||
* (see: https://doc.qt.io/qt-5/qobject.html#connect-3), that
|
||||
* guaranties that all exceptions are handled within the slot.
|
||||
*
|
||||
* NOTE: This function is incompatible with Qt private signals.
|
||||
*/
|
||||
template <typename Sender, typename Signal, typename Receiver, typename Slot>
|
||||
auto ExceptionSafeConnect(
|
||||
Sender sender, Signal signal, Receiver receiver, Slot method,
|
||||
Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
return QObject::connect(
|
||||
sender, signal, receiver,
|
||||
[sender, receiver, method](auto&&... args) {
|
||||
bool ok{true};
|
||||
try {
|
||||
(receiver->*method)(std::forward<decltype(args)>(args)...);
|
||||
} catch (const NonFatalCheckError& e) {
|
||||
PrintSlotException(&e, sender, receiver);
|
||||
ok = QMetaObject::invokeMethod(
|
||||
qApp, "handleNonFatalException",
|
||||
blockingGUIThreadConnection(),
|
||||
Q_ARG(QString, QString::fromStdString(e.what())));
|
||||
} catch (const std::exception& e) {
|
||||
PrintSlotException(&e, sender, receiver);
|
||||
ok = QMetaObject::invokeMethod(
|
||||
qApp, "handleRunawayException",
|
||||
blockingGUIThreadConnection(),
|
||||
Q_ARG(QString, QString::fromStdString(e.what())));
|
||||
} catch (...) {
|
||||
PrintSlotException(nullptr, sender, receiver);
|
||||
ok = QMetaObject::invokeMethod(
|
||||
qApp, "handleRunawayException",
|
||||
blockingGUIThreadConnection(),
|
||||
Q_ARG(QString, "Unknown failure occurred."));
|
||||
}
|
||||
assert(ok);
|
||||
},
|
||||
type);
|
||||
}
|
||||
|
||||
} // namespace GUIUtil
|
||||
|
||||
#endif // BITCOIN_QT_GUIUTIL_H
|
||||
|
|
Loading…
Add table
Reference in a new issue