aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-07-15 12:10:20 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-07-21 07:32:06 +0000
commit65c5636ad8a03fb4abd71160cbbfab49f8d8d08e (patch)
tree6a2b10e8402e448ab98ea0777aa59f35f30b638b /src/quick
parent577fb29b42d76b55290bf2c38ed07d2eaa24c9df (diff)
Avoid use-after-free in QQuickPathView
When releasing an item we always need to unregister the change listener, even if the model is already gone. The model is a public property and a QPointer. Anything can happen to it behind our back. Furthermore, we apparently don't own items and itemCache. Therefore, we have to listen to their "destroy" events and remove them from the list when those are triggered. Otherwise we operate on dangling pointers when we later releaseItem() from the dtor. Change-Id: I662b0d70b8b06d15b504c6fe1fc33384b1ae12d9 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 1b8109fc1476e255d1fdb571da884215d9791cec) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/items/qquickpathview.cpp10
-rw-r--r--src/quick/items/qquickpathview_p_p.h6
2 files changed, 13 insertions, 3 deletions
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 4052051904..9be141827c 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -146,7 +146,8 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
item->setParentItem(q);
requestedIndex = -1;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->addItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
inRequest = false;
return item;
@@ -199,11 +200,14 @@ void QQuickPathView::initItem(int index, QObject *object)
void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
{
- if (!item || !model)
+ if (!item)
return;
qCDebug(lcItemViewDelegateLifecycle) << "release" << item;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->removeItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
+ if (!model)
+ return;
QQmlInstanceModel::ReleaseFlags flags = model->release(item);
if (!flags) {
// item was not destroyed, and we no longer reference it.
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index 6c964bcb83..b245c6b5ee 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -88,6 +88,12 @@ public:
}
}
+ void itemDestroyed(QQuickItem *item) override
+ {
+ if (!items.removeOne(item))
+ itemCache.removeOne(item);
+ }
+
void scheduleLayout() {
Q_Q(QQuickPathView);
if (!layoutScheduled) {