diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-08-21 17:06:14 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-08-22 20:34:30 +0000 |
commit | c2c8369835b38630830f1b269b87d21756a8a986 (patch) | |
tree | 4b02c2f99292880bb9dc2dac7b9081607e367b97 | |
parent | 7f22f9de5f18a13c559c71c6a871f3cd97caf009 (diff) |
QtQml: Reset context object when destroying it from QObjectWrapper
There may be other objects that still hold on to the context data. We
should not leave them with a dangling context obejct.
Fixes: QTBUG-116228
Change-Id: I3dddd20b13956408d0e66c3a46e59377e45d91e5
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 1d3385e9887e912a79835c7defc878edf4ab7ec5)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 28 |
3 files changed, 35 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index dcb4887511..3caad8bde9 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1383,6 +1383,8 @@ void QObjectWrapper::destroyObject(bool lastCall) if (ddata && ddata->ownContext) { Q_ASSERT(ddata->ownContext.data() == ddata->context); ddata->ownContext->emitDestruction(); + if (ddata->ownContext->contextObject() == o) + ddata->ownContext->setContextObject(nullptr); ddata->ownContext.reset(); ddata->context = nullptr; } diff --git a/tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml b/tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml new file mode 100644 index 0000000000..a478a587df --- /dev/null +++ b/tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml @@ -0,0 +1,5 @@ +import QtQml +QtObject { + property Component c: MyItem {} + property QtObject o: c.createObject() +} diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 95e4732fd0..055c6225f3 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -51,6 +51,7 @@ private slots: void destroyContextProperty(); void numericContextProperty(); + void gcDeletesContextObject(); private: QQmlEngine engine; @@ -989,6 +990,33 @@ void tst_qqmlcontext::numericContextProperty() QCOMPARE(context->contextProperty(QLatin1String("11")).toInt(), 42); } +void tst_qqmlcontext::gcDeletesContextObject() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("gcDeletesContextObject.qml")); + + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + + QVERIFY(!o.isNull()); + + QPointer<QObject> contextObject = o->property("o").value<QObject *>(); + QVERIFY(contextObject != nullptr); + + QQmlData *data = QQmlData::get(contextObject); + QVERIFY(data); + QQmlRefPointer<QQmlContextData> context = data->ownContext; + QVERIFY(context); + QCOMPARE(context->contextObject(), contextObject); + + o->setProperty("o", QVariant::fromValue<QObject *>(nullptr)); + QCOMPARE(o->property("o").value<QObject *>(), nullptr); + engine.collectGarbage(); + + QTRY_VERIFY(contextObject.isNull()); + QCOMPARE(context->contextObject(), nullptr); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" |