From db6f1440cbe78018e442c1fb961310a4e619e8fe Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 9 Jun 2017 23:36:49 +0200 Subject: QQuickItemView: fix releaseItem() loops Calling releaseItem() destroys the item, which emits childrenChanged for the contentItem, and if at that point anything calls setFooMargin(), setContentHeight(), returnToBounds(), or many other methods that indirectly access the visibleItems list, it leads to a crash due to read after free. Add a releaseVisibleItems() helper method that makes a copy, clears the original list first, and then releases the items. Task-number: QTBUG-48394 Task-number: QTBUG-61294 Change-Id: I29e4d3870d33549e8bf789de84c67ab1826fca7d Reviewed-by: Robin Burchell --- tests/auto/quick/qquickgridview/data/releaseItems.qml | 12 ++++++++++++ tests/auto/quick/qquickgridview/tst_qquickgridview.cpp | 13 +++++++++++++ tests/auto/quick/qquicklistview/data/releaseItems.qml | 12 ++++++++++++ tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 13 +++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 tests/auto/quick/qquickgridview/data/releaseItems.qml create mode 100644 tests/auto/quick/qquicklistview/data/releaseItems.qml (limited to 'tests') diff --git a/tests/auto/quick/qquickgridview/data/releaseItems.qml b/tests/auto/quick/qquickgridview/data/releaseItems.qml new file mode 100644 index 0000000000..19d58550a4 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/releaseItems.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +GridView { + width: 400 + height: 400 + model: 100 + delegate: Rectangle { + height: 100; width: 100 + color: index % 2 ? "lightsteelblue" : "lightgray" + } + contentHeight: contentItem.children.length * 40 +} diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 1acc36c9b0..b2d6584701 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -209,6 +209,7 @@ private slots: void QTBUG_48870_fastModelUpdates(); void keyNavigationEnabled(); + void releaseItems(); private: QList toIntList(const QVariantList &list); @@ -6666,6 +6667,18 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() } } +void tst_QQuickGridView::releaseItems() +{ + QScopedPointer view(createView()); + view->setSource(testFileUrl("releaseItems.qml")); + + QQuickGridView *gridview = qobject_cast(view->rootObject()); + QVERIFY(gridview); + + // don't crash (QTBUG-61294) + gridview->setModel(123); +} + QTEST_MAIN(tst_QQuickGridView) #include "tst_qquickgridview.moc" diff --git a/tests/auto/quick/qquicklistview/data/releaseItems.qml b/tests/auto/quick/qquicklistview/data/releaseItems.qml new file mode 100644 index 0000000000..de774e5e08 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/releaseItems.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + model: 100 + delegate: Rectangle { + height: 40; width: 400 + color: index % 2 ? "lightsteelblue" : "lightgray" + } + contentHeight: contentItem.children.length * 40 +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index ff06c1e1a4..98c628068d 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -254,6 +254,7 @@ private slots: void keyNavigationEnabled(); void QTBUG_50097_stickyHeader_positionViewAtIndex(); void itemFiltered(); + void releaseItems(); private: template void items(const QUrl &source); @@ -8508,6 +8509,18 @@ void tst_QQuickListView::itemFiltered() model.setData(model.index(2), QStringLiteral("modified three"), Qt::DisplayRole); } +void tst_QQuickListView::releaseItems() +{ + QScopedPointer view(createView()); + view->setSource(testFileUrl("releaseItems.qml")); + + QQuickListView *listview = qobject_cast(view->rootObject()); + QVERIFY(listview); + + // don't crash (QTBUG-61294) + listview->setModel(123); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" -- cgit v1.2.3