aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-08-21 17:06:14 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-08-22 20:34:30 +0000
commitc2c8369835b38630830f1b269b87d21756a8a986 (patch)
tree4b02c2f99292880bb9dc2dac7b9081607e367b97
parent7f22f9de5f18a13c559c71c6a871f3cd97caf009 (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.cpp2
-rw-r--r--tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp28
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"