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 1d3385e988)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ulf Hermann 2023-08-21 17:06:14 +02:00 committed by Qt Cherry-pick Bot
parent 7f22f9de5f
commit c2c8369835
3 changed files with 35 additions and 0 deletions

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
import QtQml
QtObject {
property Component c: MyItem {}
property QtObject o: c.createObject()
}

View File

@ -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"