From 7ff9e3c3959c2ef1d7c95c8d2a1d277ccb2752a9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 10 Jan 2020 10:01:36 +0100 Subject: On QQmlEngine destruction drop singletons before type loader The singleton destruction can trigger additional types to be loaded. Fixes: QTBUG-80840 Change-Id: Ifa406b2a1cfd3b9e9b36e8005dfc0808eebf15cf Reviewed-by: Fabian Kosmale (cherry picked from commit 3c23f5371a19991771bd29c27d377c6672e46cd1) --- src/qml/qml/qqmlengine.cpp | 4 +-- .../qqmlengine/data/evilSingletonInstantiation.qml | 6 +++++ tests/auto/qml/qqmlengine/tst_qqmlengine.cpp | 31 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 7cd4bf8579..a32a13b5a4 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1074,8 +1074,6 @@ QQmlEngine::~QQmlEngine() Q_D(QQmlEngine); QJSEnginePrivate::removeFromDebugServer(this); - d->typeLoader.invalidate(); - // Emit onDestruction signals for the root context before // we destroy the contexts, engine, Singleton Types etc. that // may be required to handle the destruction signal. @@ -1091,6 +1089,8 @@ QQmlEngine::~QQmlEngine() delete d->rootContext; d->rootContext = nullptr; + + d->typeLoader.invalidate(); } /*! \fn void QQmlEngine::quit() diff --git a/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml b/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml new file mode 100644 index 0000000000..757b0c90bb --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/evilSingletonInstantiation.qml @@ -0,0 +1,6 @@ +import QtQml 2.12 +import foo.foo 1.0 + +QtObject { + objectName: Singleton.objectName +} diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 0cb6753020..ce7f509bc0 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -82,6 +82,7 @@ private slots: void singletonInstance(); void aggressiveGc(); void cachedGetterLookup_qtbug_75335(); + void createComponentOnSingletonDestruction(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1067,6 +1068,36 @@ void tst_qqmlengine::cachedGetterLookup_qtbug_75335() QVERIFY(object != nullptr); } +class EvilSingleton : public QObject +{ + Q_OBJECT +public: + QPointer m_engine; + EvilSingleton(QQmlEngine *engine) : m_engine(engine) { + connect(this, &QObject::destroyed, this, [this]() { + QQmlComponent component(m_engine); + component.setData("import QtQml 2.0\nQtObject {}", QUrl("file://Stuff.qml")); + QVERIFY(component.isReady()); + QScopedPointer obj(component.create()); + QVERIFY(obj); + }); + } +}; + +void tst_qqmlengine::createComponentOnSingletonDestruction() +{ + qmlRegisterSingletonType("foo.foo", 1, 0, "Singleton", + [](QQmlEngine *engine, QJSEngine *) -> QObject * { + return new EvilSingleton(engine); + }); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("evilSingletonInstantiation.qml")); + QVERIFY(component.isReady()); + QScopedPointer obj(component.create()); + QVERIFY(obj); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" -- cgit v1.2.3