aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2022-01-31 14:14:26 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2022-02-11 09:54:22 +0100
commit2ce8a33347e827fa4a1579b937ff5bbbadc16451 (patch)
treed5874b28ab0747cd5ea947bc219862ab823fadfe /tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
parent1b65829d3ab342230eb13493cefce0cd6c93ed79 (diff)
QQmlAdaptorModel: Do not use reparenting for lifetime managemment
In QQmlAdaptorModel, we were using QQmlStrongJSQObjectReference to ensure that a passed in model lives long enough. However, QQmlAdaptorModel uses reparenting to keep objects alive. This is not safe, as we can use QML singletons as models. Reparenting singletons messes with the engine's lifetime handling once their new parent gets deleted: The object will be marked as queuedForDeletion by QQmlData::markAsDeleted; consequently wasDeleted returns true for the object, and any ScopedObject or ObjectWrapper will return nullptr when we try to retrieve their underlying QObject. The actual object probaly does not get deleted, as it is not placed in the QML heap. Consequently the gc will ignore it. This leads to a crash when the singleton is accessed in a different place: We see that the object is non-null, create a ScopedObject for it, and then try to later access the ScopedObject's underlying object (assuming that it must be non-null, because we already checked for the actual object being non-null). However, due to the reasons outlined above, we actually receive a null pointer, and thus encounter a crash. To avoid he issue, we change the lifetime management strategy: Instead of using the parent to keep the object alive, we now use a QV4::PersistentValue. Fixes: QTBUG-100260 Change-Id: I266e6ef94c4f079de3da2742d6fb8d61df5a64ce Reviewed-by: Andrei Golubev <andrei.golubev@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 6901eacff40a7d8781e20fb5bcfd28d7526b589b) (cherry picked from commit ce8db0672557cef7942df061f52ccdf65fa250f6) Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests/auto/quick/qquicklistview/tst_qquicklistview.cpp')
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp24
1 files changed, 24 insertions, 0 deletions
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index d3deb513d0..7b17c014d5 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -33,6 +33,8 @@
#include <QtGui/QStyleHints>
#include <QtQuick/qquickview.h>
#include <QtQuickTest/QtQuickTest>
+#include <QStringListModel>
+#include <QQmlApplicationEngine>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
@@ -302,6 +304,9 @@ private slots:
void dragDelegateWithMouseArea();
void dragDelegateWithMouseArea_data();
+
+ void singletonModelLifetime();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -10200,6 +10205,25 @@ void tst_QQuickListView::dragDelegateWithMouseArea_data()
}
}
+class SingletonModel : public QStringListModel
+{
+ Q_OBJECT
+public:
+ SingletonModel(QObject* parent = nullptr) : QStringListModel(parent) { }
+};
+
+void tst_QQuickListView::singletonModelLifetime()
+{
+ // this does not really test any functionality of listview, but we do not have a good way
+ // to unit test QQmlAdaptorModel in isolation.
+ qmlRegisterSingletonType<SingletonModel>("test", 1, 0, "SingletonModel",
+ [](QQmlEngine* , QJSEngine*) -> QObject* { return new SingletonModel; });
+
+ QQmlApplicationEngine engine(testFile("singletonModelLifetime.qml"));
+ // needs event loop iteration for callLater to execute
+ QTRY_VERIFY(engine.rootObjects().first()->property("alive").toBool());
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"