aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-06-09 23:36:49 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2017-06-12 15:32:45 +0000
commitdb6f1440cbe78018e442c1fb961310a4e619e8fe (patch)
treed1e88d2f82bd38ee1959bed6a19d0c074d8c05f0 /src/quick/items
parent939f07695b853a4da2e237c5f1c3d50e34f9c45c (diff)
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 <robin.burchell@crimson.no>
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/qquickgridview.cpp4
-rw-r--r--src/quick/items/qquickitemview.cpp8
-rw-r--r--src/quick/items/qquickitemview_p_p.h9
-rw-r--r--src/quick/items/qquicklistview.cpp4
4 files changed, 13 insertions, 12 deletions
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index fd78c46a16..c570b95a21 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -495,9 +495,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
// We've jumped more than a page. Estimate which items are now
// visible and fill from there.
int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex += count;
if (modelIndex >= model->count())
modelIndex = model->count() - 1;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 555db03962..084b1f197a 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -380,9 +380,7 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
if (isComponentComplete()) {
- for (FxViewItem *item : qAsConst(d->visibleItems))
- d->releaseItem(item);
- d->visibleItems.clear();
+ d->releaseVisibleItems();
d->releaseItem(d->currentItem);
d->currentItem = 0;
d->updateSectionCriteria();
@@ -1743,9 +1741,7 @@ void QQuickItemViewPrivate::clear()
currentChanges.reset();
timeline.clear();
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
visibleIndex = 0;
for (FxViewItem *item : qAsConst(releasePendingTransition)) {
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 3087682ac7..b6353246e8 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -269,6 +269,15 @@ public:
q->polish();
}
+ void releaseVisibleItems() {
+ // make a copy and clear the visibleItems first to avoid destroyed
+ // items being accessed during the loop (QTBUG-61294)
+ const QList<FxViewItem *> oldVisible = visibleItems;
+ visibleItems.clear();
+ for (FxViewItem *item : oldVisible)
+ releaseItem(item);
+ }
+
QPointer<QQmlInstanceModel> model;
QVariant modelVariant;
int itemCount;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index f739115e6b..18f9b8512d 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -660,9 +660,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal
int newModelIdx = qBound(0, modelIndex + count, model->count());
count = newModelIdx - modelIndex;
if (count) {
- for (FxViewItem *item : qAsConst(visibleItems))
- releaseItem(item);
- visibleItems.clear();
+ releaseVisibleItems();
modelIndex = newModelIdx;
visibleIndex = modelIndex;
visiblePos = itemEnd + count * (averageSize + spacing);