diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-11-29 11:28:49 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-11-30 09:09:36 +0000 |
commit | b17091b0006e41c0bb4ddf77dbbc09621d809aea (patch) | |
tree | fd27f9b48ee209b13d545fa8df46d147b0566d24 /tests/auto | |
parent | d0a52c72b5756787ceb6094117cd71d935badc06 (diff) |
QML: Also clear outerContext's contextObject on destruction
A QObject can not only be set as contextObject of the own context, but
also as contextObject of the outerContext of a respective QQmlData. This
can be seen in QQmlObjectCreator::createInstance(...) if isContextObject
is true.
Therefore, when catching a QObject deletion we need to clear the pointer
in the outerContext if that refers to the object being deleted.
Fixes: QTBUG-71037
Change-Id: Ib6ba99bd5336f7582486b2128515021245370c60
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/MyItem.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/outerContextObject.qml | 18 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 58 |
3 files changed, 81 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlcontext/data/MyItem.qml b/tests/auto/qml/qqmlcontext/data/MyItem.qml new file mode 100644 index 0000000000..2ffd984dfa --- /dev/null +++ b/tests/auto/qml/qqmlcontext/data/MyItem.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + Component.onCompleted: 5 + 5 +} diff --git a/tests/auto/qml/qqmlcontext/data/outerContextObject.qml b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml new file mode 100644 index 0000000000..992b760915 --- /dev/null +++ b/tests/auto/qml/qqmlcontext/data/outerContextObject.qml @@ -0,0 +1,18 @@ +import QtQml 2.2 + +QtObject { + id: window + + property Component itemComponent: Qt.createComponent("MyItem.qml") + property MyItem item + + property Timer timer: Timer { + running: true + interval: 10 + repeat: true + onTriggered: { + item = itemComponent.createObject(null, {}); + gc(); + } + } +} diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 990e364c76..5838193a6b 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -28,6 +28,7 @@ #include <qtest.h> #include <QDebug> +#include <QTimer> #include <QQmlEngine> #include <QQmlContext> #include <QQmlComponent> @@ -68,6 +69,8 @@ private slots: void contextViaClosureAfterDestruction(); void contextLeak(); + void outerContextObject(); + private: QQmlEngine engine; }; @@ -815,6 +818,61 @@ void tst_qqmlcontext::contextLeak() QVERIFY(scriptContext.isNull()); } + +static bool buildObjectList(QQmlContext *ctxt) +{ + static QHash<QObject *, QString> deletedObjects; + QQmlContextData *p = QQmlContextData::get(ctxt); + QObject *object = p->contextObject; + if (object) { + // If the object was actually deleted this is likely to crash in one way or another. + // Either the memory is still intact, then we will probably find the objectName, or it is + // not, then the connect() below is likely to fail. + if (deletedObjects.contains(object) && deletedObjects[object] == object->objectName()) + return false; + QObject::connect(object, &QObject::destroyed, [object]() { + object->setObjectName(QString::number(deletedObjects.size())); + deletedObjects.insert(object, object->objectName()); + }); + } + + QQmlContextData *child = p->childContexts; + while (child) { + if (!buildObjectList(child->asQQmlContext())) + return false; + child = child->nextChild; + } + + return true; +} + +void tst_qqmlcontext::outerContextObject() +{ + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl("outerContextObject.qml")); + QVERIFY(component.isReady()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + int iterations = 0; + QTimer timer; + timer.setInterval(1); + QObject::connect(&timer, &QTimer::timeout, &engine, [&]() { + if (!buildObjectList(engine.rootContext())) { + iterations = 100; + timer.stop(); + QFAIL("Deleted object found as context object"); + } else { + ++iterations; + } + }); + timer.start(); + + QTRY_VERIFY(iterations >= 100); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" |