From c2c8369835b38630830f1b269b87d21756a8a986 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 21 Aug 2023 17:06:14 +0200 Subject: [PATCH] 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 Reviewed-by: Qt CI Bot (cherry picked from commit 1d3385e9887e912a79835c7defc878edf4ab7ec5) Reviewed-by: Qt Cherry-pick Bot --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 ++ .../data/gcDeletesContextObject.qml | 5 ++++ .../auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/auto/qml/qqmlcontext/data/gcDeletesContextObject.qml 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 o(c.create()); + + QVERIFY(!o.isNull()); + + QPointer contextObject = o->property("o").value(); + QVERIFY(contextObject != nullptr); + + QQmlData *data = QQmlData::get(contextObject); + QVERIFY(data); + QQmlRefPointer context = data->ownContext; + QVERIFY(context); + QCOMPARE(context->contextObject(), contextObject); + + o->setProperty("o", QVariant::fromValue(nullptr)); + QCOMPARE(o->property("o").value(), nullptr); + engine.collectGarbage(); + + QTRY_VERIFY(contextObject.isNull()); + QCOMPARE(context->contextObject(), nullptr); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc"