diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-02-28 15:28:34 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-03-01 08:55:32 +0100 |
commit | 79e885537f8546a18d7d9d902d6efe40b1915c96 (patch) | |
tree | ed4d080063e3fbc32632fd7a0d2d0ac8bab370e9 | |
parent | 074b66e0073b55d32060ffd542a02c811ad763a8 (diff) |
QQuickLoader: Check for QQmlEngine before using it
The loader's context may have been removed from the context hierarchy or
it may not have a context in the first place. We should not crash then.
Pick-to: 5.15 6.2 6.3
Fixes: QTBUG-67950
Change-Id: I1058d5b1f978aa040f8b2f018c4357dd7a3ef333
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r-- | src/quick/items/qquickloader.cpp | 12 | ||||
-rw-r--r-- | tests/auto/quick/qquickloader/data/noEngine.qml | 32 | ||||
-rw-r--r-- | tests/auto/quick/qquickloader/tst_qquickloader.cpp | 15 |
3 files changed, 56 insertions, 3 deletions
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index bde39d99bd..ea1aa7b0c9 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -1041,9 +1041,15 @@ void QQuickLoaderPrivate::createComponent() const QQmlComponent::CompilationMode mode = asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous; - QQmlContext *context = qmlContext(q); - component.setObject(new QQmlComponent( - context->engine(), context->resolvedUrl(source), mode, q), q); + if (QQmlContext *context = qmlContext(q)) { + if (QQmlEngine *engine = context->engine()) { + component.setObject(new QQmlComponent( + engine, context->resolvedUrl(source), mode, q), q); + return; + } + } + + qmlWarning(q) << "createComponent: Cannot find a QML engine."; } #include <moc_qquickloader_p.cpp> diff --git a/tests/auto/quick/qquickloader/data/noEngine.qml b/tests/auto/quick/qquickloader/data/noEngine.qml new file mode 100644 index 0000000000..19e619f32e --- /dev/null +++ b/tests/auto/quick/qquickloader/data/noEngine.qml @@ -0,0 +1,32 @@ +import QtQuick 2 + +Item { + id: root + property bool a: false + property int changes: 0 + onAChanged: { + m.model = 0 + m.model = 1 + ++changes; + } + + Repeater { + id: m + model: 1 + + Item { + Timer { + onTriggered: { + root.a = true + l.source = "loaded.qml" + } + interval: 0 + running: true + } + + Loader { + id: l + } + } + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index cf1c4fcce0..e990e94bc3 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -134,6 +134,7 @@ private slots: void setSourceAndCheckStatus(); void asyncLoaderRace(); + void noEngine(); }; Q_DECLARE_METATYPE(QList<QQmlError>) @@ -1533,6 +1534,20 @@ void tst_QQuickLoader::asyncLoaderRace() QCOMPARE(loader->item(), nullptr); } +void tst_QQuickLoader::noEngine() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("noEngine.qml"); + QQmlComponent component(&engine, url); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> o(component.create()); + + const QString message = url.toString() + + QStringLiteral(":27:13: QML Loader: createComponent: Cannot find a QML engine."); + QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); + QTRY_COMPARE(o->property("changes").toInt(), 1); +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" |