From 9148ab4d8dd2fe4221aca1f1e2af1ad17835b6bd Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 19 Aug 2025 15:25:48 +0200 Subject: QtQml: Store detached Sequence objects on the JS heap While the Sequence is detached it is subject to the GC or unrelated C++ code deleting objects from its internals. Since it's then not the owning object's responsibility to track this anymore, we need to track it ourselves. The way to do it is to use the existing V4 objects. We don't have to store the sequence on the JS heap if it cannot store a QObject. Only lists of variants or pointers are affected. This independently fixes QTBUG-129972 for 6.8 where VariantAssociationObject does not exist, yet. This is because the detached sequence shown in that bug won't need to be written back to anymore in order to stay up to date. Pick-to: 6.10 6.9 6.8 Fixes: QTBUG-129972 Task-number: QTBUG-139025 Change-Id: Ib469c6c65f2f96041e2ad2fd106f8cd60a182e13 Reviewed-by: Sami Shalayel --- tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp') diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index 8bddd2cca0..7e116e9d6f 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -1762,9 +1762,15 @@ void tst_QmlCppCodegen::detachedReferences() QVERIFY(collectable2); QSignalSpy spy2(collectable2, &QObject::destroyed); + const QVariantList list = d->getList(); + QObject *collectable3 = list[2].value(); + QVERIFY(collectable3); + QSignalSpy spy3(collectable3, &QObject::destroyed); + // The detached containers retain their types. QCOMPARE(d->property("markedMap").metaType(), QMetaType::fromType()); QCOMPARE(d->property("markedHash").metaType(), QMetaType::fromType()); + QCOMPARE(d->property("markedList").metaType(), QMetaType::fromType()); engine.collectGarbage(); QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); @@ -1772,9 +1778,10 @@ void tst_QmlCppCodegen::detachedReferences() QCOMPARE(spy1.count(), 0); QCOMPARE(spy2.count(), 0); + QCOMPARE(spy3.count(), 0); - // Resetting the hash alone does not cause collectible1 to be collected - // because it's also in the map (recursively). + // Resetting the hash alone does not cause the collectibles to be collected + // because they're also in the map and the list (recursively). d->setProperty("markedHash", QVariant()); engine.collectGarbage(); @@ -1783,15 +1790,30 @@ void tst_QmlCppCodegen::detachedReferences() QCOMPARE(spy1.count(), 0); QCOMPARE(spy2.count(), 0); + QCOMPARE(spy3.count(), 0); + // Resetting the map still does not cause the collectibles to be collected + // because they're also in the list (recursively). d->setProperty("markedMap", QVariant()); engine.collectGarbage(); QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); + QCOMPARE(spy1.count(), 0); + QCOMPARE(spy2.count(), 0); + QCOMPARE(spy3.count(), 0); + + // Resetting the list finally causes everything to be collected. + d->setProperty("markedList", QVariant()); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + QCOMPARE(spy1.count(), 1); QCOMPARE(spy2.count(), 1); + QCOMPARE(spy3.count(), 1); } void tst_QmlCppCodegen::dialogButtonBox() @@ -3421,11 +3443,13 @@ void tst_QmlCppCodegen::listConversion() QStringList strings = o->property("s").value(); QCOMPARE(strings, QStringList({u"Horst 1"_s, u"Horst 2"_s, u"Horst 3"_s})); + // Since this is stored as list, the exact types can't be retained. + // For JavaScript any number is double, and any nullptr is just null. QVariantList vars = o->property("v").toList(); QCOMPARE(vars, QVariantList({ QString(), - QVariant::fromValue(3), - QVariant::fromValue(nullptr) + QVariant::fromValue(3), + QVariant::fromValue(nullptr) })); QCOMPARE(o->property("numbers").value>(), (QList{1, 2})); -- cgit v1.2.3