aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-02-15 14:12:47 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-02-20 22:46:15 +0000
commita88a9f4943652699ca48047a16ca5df88b0c1afe (patch)
tree545a9b6f951144180527c68523e2bf95edbd5383
parent723fc1ade8d17d60a71f75512afc02422d17a5ac (diff)
QtQml: Don't let objects be deleted during incubation
As long as the incubator object is alive, it should hold on to the object being incubated. Anything else makes no sense. Re-use the "valuemap" slot to hold on to the object once its ready. Pick-to: 6.5 Fixes: QTBUG-119911 Change-Id: Ia9823aced5ec16a8da00e61ad7d606c63e40ed31 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 95965ba19f6a1cc04d8bc04e2c55ececcd87edbb) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 5723be147af1a77076924da1e422c39927140a46)
-rw-r--r--src/qml/qml/qqmlcomponent.cpp25
-rw-r--r--tests/auto/qml/qqmlincubator/data/garbageCollection2.qml12
-rw-r--r--tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp6
3 files changed, 33 insertions, 10 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 11ef88444e..0d2885209e 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1498,7 +1498,7 @@ namespace QV4 {
namespace Heap {
#define QmlIncubatorObjectMembers(class, Member) \
- Member(class, HeapValue, HeapValue, valuemap) \
+ Member(class, HeapValue, HeapValue, valuemapOrObject) \
Member(class, HeapValue, HeapValue, statusChanged) \
Member(class, Pointer, QmlContext *, qmlContext) \
Member(class, NoMark, QQmlComponentIncubator *, incubator) \
@@ -1911,7 +1911,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
r->setPrototypeOf(p);
if (!valuemap->isUndefined())
- r->d()->valuemap.set(scope.engine, valuemap);
+ r->d()->valuemapOrObject.set(scope.engine, valuemap);
r->d()->qmlContext.set(scope.engine, v4->qmlContext());
r->d()->parent = parent;
@@ -2014,7 +2014,7 @@ QQmlComponentExtension::~QQmlComponentExtension()
void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
{
Object::init();
- valuemap.set(internalClass->engine, QV4::Value::undefinedValue());
+ valuemapOrObject.set(internalClass->engine, QV4::Value::undefinedValue());
statusChanged.set(internalClass->engine, QV4::Value::undefinedValue());
parent.init();
qmlContext.set(internalClass->engine, nullptr);
@@ -2031,13 +2031,13 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *re
{
QQmlComponent_setQmlParent(o, d()->parent);
- if (!d()->valuemap.isUndefined()) {
+ if (!d()->valuemapOrObject.isUndefined()) {
QV4::ExecutionEngine *v4 = engine();
QV4::Scope scope(v4);
QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o));
QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext);
QQmlComponentPrivate::setInitialProperties(
- v4, qmlCtxt, obj, d()->valuemap, requiredProperties, o,
+ v4, qmlCtxt, obj, d()->valuemapOrObject, requiredProperties, o,
QQmlIncubatorPrivate::get(d()->incubator)->creator.data());
}
}
@@ -2045,13 +2045,18 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o, RequiredProperties *re
void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
QV4::Scope scope(engine());
- // hold the incubated object in a scoped value to prevent it's destruction before this method returns
- QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, d()->incubator->object()));
+
+ QObject *object = d()->incubator->object();
if (s == QQmlIncubator::Ready) {
- Q_ASSERT(QQmlData::get(d()->incubator->object()));
- QQmlData::get(d()->incubator->object())->explicitIndestructibleSet = false;
- QQmlData::get(d()->incubator->object())->indestructible = false;
+ // We don't need the arguments anymore, but we still want to hold on to the object so
+ // that it doesn't get gc'd
+ d()->valuemapOrObject.set(scope.engine, QV4::QObjectWrapper::wrap(scope.engine, object));
+
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(ddata);
+ ddata->explicitIndestructibleSet = false;
+ ddata->indestructible = false;
}
QV4::ScopedFunctionObject f(scope, d()->statusChanged);
diff --git a/tests/auto/qml/qqmlincubator/data/garbageCollection2.qml b/tests/auto/qml/qqmlincubator/data/garbageCollection2.qml
new file mode 100644
index 0000000000..b5ba531ede
--- /dev/null
+++ b/tests/auto/qml/qqmlincubator/data/garbageCollection2.qml
@@ -0,0 +1,12 @@
+import QtQml
+QtObject {
+ property Component comp: Component {
+ QtObject {}
+ }
+
+ property QtObject incubated: {
+ var i = comp.incubateObject(null, {}, Qt.Synchronous);
+ gc();
+ return i.object
+ }
+}
diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
index 1baf61574e..eaa59f036d 100644
--- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
+++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp
@@ -1168,6 +1168,12 @@ void tst_qqmlincubator::garbageCollection()
// verify incubator is correctly collected now that incubation is complete and all references are gone
engine.collectGarbage();
QVERIFY(weakIncubatorRef.isNullOrUndefined());
+
+ QQmlComponent component2(&engine, testFileUrl("garbageCollection2.qml"));
+ QVERIFY2(component2.isReady(), qPrintable(component2.errorString()));
+ QScopedPointer<QObject> obj2(component2.create());
+ QVERIFY(!obj2.isNull());
+ QVERIFY(obj2->property("incubated").value<QObject *>() != nullptr);
}
void tst_qqmlincubator::requiredProperties()