summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@qt.io>2024-03-06 15:32:08 +0100
committerRobert Griebl <robert.griebl@qt.io>2024-03-07 09:27:50 +0100
commit23b39347af03a40af4d19be9793f0f93a691a78f (patch)
treeedcb8693798a1eb4d45756cf74e7f34dfc10eae2
parentea49063b02733e3ec8caaf39a610fb70d24d5b0a (diff)
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: <what()>" 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 Pick-to: 6.7 6.6 6.5 Reviewed-by: Dominik Holland <dominik.holland@qt.io>
-rw-r--r--examples/applicationmanager/custom-appman/custom-appman.cpp19
-rw-r--r--examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc4
-rw-r--r--src/main-lib/main.h2
-rw-r--r--src/main-lib/mainmacro.h23
-rw-r--r--src/tools/appman/appman.cpp33
-rw-r--r--src/tools/launcher-qml/launcher-qml.cpp10
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<Main> a;
+ std::unique_ptr<Configuration> cfg;
- Configuration cfg;
- cfg.parseWithArguments(QCoreApplication::arguments());
+ try {
+ a = std::make_unique<Main>(argc, argv, Main::InitFlag::ForkSudoServer
+ | Main::InitFlag::InitializeLogging);
+ cfg = std::make_unique<Configuration>();
+ 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 <QtAppManMain/main.h>
\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<Main>
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<QtAM::Main> a; \
+ std::unique_ptr<QtAM::Configuration> 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<QtAM::Main>(argc, argv, QtAM::Main::InitFlag::ForkSudoServer \
+ | QtAM::Main::InitFlag::InitializeLogging); \
+ cfg = std::make_unique<QtAM::Configuration>(); \
+ 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<Main> a;
+ std::unique_ptr<Configuration> 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<Main>(argc, argv, Main::InitFlag::ForkSudoServer
+ | Main::InitFlag::InitializeLogging);
+ cfg = std::make_unique<Configuration>(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<ApplicationMain> am;
+ std::unique_ptr<Controller> 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> 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)