From 0b6e1dab86fcf4c4b6b2daae2beb20552be0bd59 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Wed, 6 Mar 2024 15:32:08 +0100 Subject: Fix exception handling after Q*Application::exec() Uncaught exceptions thrown after we call exec() are originating from user code and we should not be catching those in our top-level catch handler. This will just print "ERROR: " without any context and make it look like the error is coming from the AM itself. Instead we need to run the event loop without a try/catch handler, so stray exception from user code go directly to our set_terminate handler in the CrashHandler class, which preserves as much context as possible and prints out a lot more useful meta data for debugging. Change-Id: Icc0432d5a6c5db85de439cafab89d05aa88b5891 Reviewed-by: Dominik Holland (cherry picked from commit 23b39347af03a40af4d19be9793f0f93a691a78f) --- .../custom-appman/custom-appman.cpp | 19 +++++++------ .../custom-appman/doc/src/custom-appman.qdoc | 4 +-- src/main-lib/main.h | 2 +- src/main-lib/mainmacro.h | 23 ++++++++------- src/tools/appman/appman.cpp | 33 +++++++++++++--------- src/tools/launcher-qml/launcher-qml.cpp | 10 +++---- 6 files changed, 51 insertions(+), 40 deletions(-) diff --git a/examples/applicationmanager/custom-appman/custom-appman.cpp b/examples/applicationmanager/custom-appman/custom-appman.cpp index 28f7a1b9..3ec4c6e5 100644 --- a/examples/applicationmanager/custom-appman/custom-appman.cpp +++ b/examples/applicationmanager/custom-appman/custom-appman.cpp @@ -23,21 +23,24 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) QCoreApplication::setApplicationName(u"Custom Application Manager"_s); QCoreApplication::setApplicationVersion(u"0.1"_s); - try { - Main a(argc, argv, Main::InitFlag::ForkSudoServer | Main::InitFlag::InitializeLogging); + std::unique_ptr
a; + std::unique_ptr cfg; - Configuration cfg; - cfg.parseWithArguments(QCoreApplication::arguments()); + try { + a = std::make_unique
(argc, argv, Main::InitFlag::ForkSudoServer + | Main::InitFlag::InitializeLogging); + cfg = std::make_unique(); + cfg->parseWithArguments(QCoreApplication::arguments()); - a.setup(&cfg); - a.loadQml(cfg.loadDummyData()); - a.showWindow(cfg.fullscreen() && !cfg.noFullscreen()); + a->setup(cfg.get()); + a->loadQml(); + a->showWindow(cfg->fullscreen() && !cfg->noFullscreen()); - return Main::exec(); } catch (const std::exception &e) { qCritical() << "ERROR:" << e.what(); return 2; } + return Main::exec(); } #endif diff --git a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc index ee6c1b82..55f9fc4f 100644 --- a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc +++ b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc @@ -36,7 +36,7 @@ them is both intended and required, so we need to set the define \c AM_COMPILING The following is a breakdown of the minimal code necessary: \quotefromfile applicationmanager/custom-appman/custom-appman.cpp -\skipto #include +\skipto #include \printuntil QT_USE_NAMESPACE_AM The application manager is split into functional building blocks. These include statements @@ -49,7 +49,7 @@ the application manager's symbols are namespaced - \c QT_USE_NAMESPACE_AM expand Generally, it's a good idea to set an application name and version. -\printuntil Main a +\printuntil a = std::make_unique
This \c try block is the heart of the custom application manager. You need to create a \c Main object, which is a class derived from QGuiApplication (or QApplication, if widgets support is diff --git a/src/main-lib/main.h b/src/main-lib/main.h index fc2e2672..ddb6704e 100644 --- a/src/main-lib/main.h +++ b/src/main-lib/main.h @@ -72,7 +72,7 @@ public: bool isRunningOnEmbedded() const; void setup(const Configuration *cfg) noexcept(false); - void loadQml(bool loadDummyData) noexcept(false); + void loadQml(bool loadDummyData = false) noexcept(false); void showWindow(bool showFullscreen); Q_INVOKABLE void shutDown(int exitCode = 0); diff --git a/src/main-lib/mainmacro.h b/src/main-lib/mainmacro.h index 2b99fcba..f27af6a6 100644 --- a/src/main-lib/mainmacro.h +++ b/src/main-lib/mainmacro.h @@ -14,21 +14,24 @@ QT_END_NAMESPACE_AM #define QT_AM_MAIN() \ Q_DECL_EXPORT int main(int argc, char *argv[]) \ { \ + std::unique_ptr a; \ + std::unique_ptr cfg; \ +\ try { \ - QtAM::Main a(argc, argv, QtAM::Main::InitFlag::ForkSudoServer | QtAM::Main::InitFlag::InitializeLogging); \ - \ - QtAM::Configuration cfg; \ - cfg.parseWithArguments(QCoreApplication::arguments()); \ - \ - a.setup(&cfg); \ - a.loadQml(cfg.loadDummyData()); \ - a.showWindow(cfg.fullscreen() && !cfg.noFullscreen()); \ - \ - return QtAM::MainBase::exec(); \ + a = std::make_unique(argc, argv, QtAM::Main::InitFlag::ForkSudoServer \ + | QtAM::Main::InitFlag::InitializeLogging); \ + cfg = std::make_unique(); \ + cfg->parseWithArguments(QCoreApplication::arguments()); \ +\ + a->setup(cfg.get()); \ + a->loadQml(); \ + a->showWindow(cfg->fullscreen() && !cfg->noFullscreen()); \ } catch (const std::exception &e) { \ qCritical() << "ERROR:" << e.what(); \ return 2; \ } \ +\ + return QtAM::Main::exec(); \ } #endif // MAINMACRO_H diff --git a/src/tools/appman/appman.cpp b/src/tools/appman/appman.cpp index 06cc3ce6..02f32424 100644 --- a/src/tools/appman/appman.cpp +++ b/src/tools/appman/appman.cpp @@ -46,26 +46,31 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) QCoreApplication::setOrganizationDomain(u"qt-project.org"_s); QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_AM_VERSION_STR)); - try { - Main a(argc, argv, Main::InitFlag::ForkSudoServer | Main::InitFlag::InitializeLogging); - - Configuration cfg(additionalDescription, onlyOnePositionalArgument); - cfg.parseWithArguments(QCoreApplication::arguments()); + std::unique_ptr
a; + std::unique_ptr cfg; -#if defined(AM_TESTRUNNER) - TestRunner::setup(&cfg); -#endif - a.setup(&cfg); - a.loadQml(cfg.loadDummyData()); - a.showWindow(cfg.fullscreen() && !cfg.noFullscreen()); + try { + a = std::make_unique
(argc, argv, Main::InitFlag::ForkSudoServer + | Main::InitFlag::InitializeLogging); + cfg = std::make_unique(additionalDescription, onlyOnePositionalArgument); + cfg->parseWithArguments(QCoreApplication::arguments()); #if defined(AM_TESTRUNNER) - return TestRunner::exec(a.qmlEngine()); -#else - return Main::exec(); + TestRunner::setup(cfg.get()); #endif + a->setup(cfg.get()); + a->loadQml(cfg->loadDummyData()); + a->showWindow(cfg->fullscreen() && !cfg->noFullscreen()); } catch (const Exception &e) { qCCritical(LogSystem).noquote() << "ERROR:" << e.errorString(); return 2; } + + // we want the exec() outside of the try/catch block, so stray user exceptions trigger the + // CrashHandler's set_terminate callback. +#if defined(AM_TESTRUNNER) + return TestRunner::exec(a->qmlEngine()); +#else + return Main::exec(); +#endif } diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp index c0953385..55b2a945 100644 --- a/src/tools/launcher-qml/launcher-qml.cpp +++ b/src/tools/launcher-qml/launcher-qml.cpp @@ -82,6 +82,7 @@ int main(int argc, char *argv[]) Logging::initialize(); std::unique_ptr am; + std::unique_ptr controller; // this needs to die BEFORE qApp does try { const QString socket = QDir(qEnvironmentVariable("XDG_RUNTIME_DIR")) @@ -116,8 +117,6 @@ int main(int argc, char *argv[]) StartupTimer::instance()->checkpoint("after basic initialization"); - std::unique_ptr controller; // this needs to die BEFORE qApp does - if (!directLoadManifest.isEmpty()) { QString directLoadAppId; qsizetype appPos = directLoadManifest.indexOf(u"@"_s); @@ -136,13 +135,14 @@ int main(int argc, char *argv[]) StartupTimer::instance()->checkpoint("after dbus initialization"); controller.reset(new Controller(am.get(), quicklaunched)); } - - return am->exec(); - } catch (const std::exception &e) { qCCritical(LogQmlRuntime) << "ERROR:" << e.what(); return 2; } + + // we want the exec() outside of the try/catch block, so stray user exceptions trigger the + // CrashHandler's set_terminate callback. + return ApplicationMainBase::exec(); } Controller::Controller(ApplicationMain *am, bool quickLaunched) -- cgit v1.2.3