diff options
| author | Vladimir Belyavsky <belyavskyv@gmail.com> | 2026-09-24 12:06:00 +0300 |
|---|---|---|
| committer | Vladimir Belyavsky <belyavskyv@gmail.com> | 2026-09-28 15:21:41 +0000 |
| commit | 83d091dcb160d3f0c4a8bc9df8b8a9a934ac82a1 (patch) | |
| tree | bb8ad91e3b8d3a4294d2b6ebb3a0ae0dbb891ffa /src | |
| parent | dd5e944dcffc4de702a996b35aeffe7aa7d844a4 (diff) | |
QQuickItemView: don't leave dangling entries in unrequestedItems
b0b1c1de68a1cc15f6304bb85d0c57a49499f866 ("QQuickItemView: register
Destroyed listener when storing an item") added a loop at the end of
~QQuickItemView that walks unrequestedItems and dereferences the stored
raw pointers to remove our Destroyed listener from each item. This is
only safe while every entry points at a live item. The listener is what
keeps that true: when the item is deleted, it calls itemDestroyed(),
which removes the entry from the hash.
releaseItem() can break that invariant. An item stored with isClearing
== false gets both the entry and the listener. Releasing it again while
the view is being cleared (isClearing == true) removes the listener but
leaves the entry, so itemDestroyed() never runs for it and the entry is
never dropped. Once the item is freed, the destructor loop dereferences
a dangling pointer, causing a use-after-free crash.
For instance, deactivating a Loader that hosts a ListView invalidates
the delegate contexts synchronously while the deferred delete is still
pending: the delegate ends up in unrequestedItems, and its
currentItem/visibleItems twin is released again during clear(true).
Remove the entry from unrequestedItems whenever the listener is removed,
keeping the two in sync so the destructor never walks a freed pointer.
Fixes: QTBUG-150769
Pick-to: 6.12
Change-Id: Ide32473f3fea373749197c969eaff6d13869c32d
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src')
| -rw-r--r-- | src/quick/items/qquickitemview.cpp | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 956b4a46b4..cf4475e00a 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2681,8 +2681,10 @@ bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::Reu } } - if (removeItemChangeListener) + if (removeItemChangeListener) { + unrequestedItems.remove(quickItem); QQuickItemPrivate::get(quickItem)->removeItemChangeListener(this, itemChangeListenerTypes); + } #if QT_CONFIG(quick_viewtransitions) delete item->transitionableItem; item->transitionableItem = nullptr; |
