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>
This commit is contained in:
Ulf Hermann 2022-02-28 15:28:34 +01:00
parent 074b66e007
commit 79e885537f
3 changed files with 56 additions and 3 deletions

View File

@ -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>

View File

@ -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
}
}
}
}

View File

@ -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"