mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 14:19:59 -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>"));
|
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
|
} // namespace GUIUtil
|
||||||
|
|
|
@ -9,18 +9,23 @@
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
|
#include <util/check.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QItemDelegate>
|
#include <QItemDelegate>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QMetaObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
class QValidatedLineEdit;
|
class QValidatedLineEdit;
|
||||||
class SendCoinsRecipient;
|
class SendCoinsRecipient;
|
||||||
|
@ -332,6 +337,53 @@ namespace GUIUtil
|
||||||
*/
|
*/
|
||||||
QString MakeHtmlLink(const QString& source, const QString& link);
|
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
|
} // namespace GUIUtil
|
||||||
|
|
||||||
#endif // BITCOIN_QT_GUIUTIL_H
|
#endif // BITCOIN_QT_GUIUTIL_H
|
||||||
|
|
Loading…
Add table
Reference in a new issue