aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@jollamobile.com>2015-02-05 12:00:00 +0100
committerGunnar Sletta <gunnar@sletta.org>2015-02-06 07:02:51 +0000
commit0b60867f80e207a9ccc27cc337116d1c6fc928bd (patch)
tree26d56168203d71613ce50a166ef1a47c80089911
parent566b23df8c31b50fc514a069564d23121d0f4ef9 (diff)
Fix crash when QQuickWindow::updatePolish() deletes QQuickItems.
When an item is deleted as a result of an updatePolish() call, it will be removed from the itemsToPolish set. However, updatePolish() internally works on a copy of the itemsToPolish set because changes to the set would invalidate its iterator. Because it is a copy will still contain the deleted item. Fix this by simplifying the algorithm to instead pick items one by one from the itemsToPolish set until it is empty. The recursion guard has been increased because we're not decrementing it for every single QQuickItem::updatePolish() call. Task-number: QTBUG-42913 Change-Id: If7ab7f7616b01daf4d3ed843f927c163dfb03843 Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
-rw-r--r--src/quick/items/qquickwindow.cpp30
1 files changed, 16 insertions, 14 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 129c07da1d..f21a93b83c 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -249,20 +249,22 @@ void QQuickWindow::focusInEvent(QFocusEvent *ev)
void QQuickWindowPrivate::polishItems()
{
- int maxPolishCycles = 100000;
-
- while (!itemsToPolish.isEmpty() && --maxPolishCycles > 0) {
- QSet<QQuickItem *> itms = itemsToPolish;
- itemsToPolish.clear();
-
- for (QSet<QQuickItem *>::iterator it = itms.begin(); it != itms.end(); ++it) {
- QQuickItem *item = *it;
- QQuickItemPrivate::get(item)->polishScheduled = false;
- item->updatePolish();
- }
- }
-
- if (maxPolishCycles == 0)
+ // An item can trigger polish on another item, or itself for that matter,
+ // during its updatePolish() call. Because of this, we cannot simply
+ // iterate through the set, we must continue pulling items out until it
+ // is empty.
+ // In the case where polish is called from updatePolish() either directly
+ // or indirectly, we use a recursionSafeguard to print a warning to
+ // the user.
+ int recursionSafeguard = INT_MAX;
+ while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) {
+ QQuickItem *item = *itemsToPolish.begin();
+ itemsToPolish.remove(item);
+ QQuickItemPrivate::get(item)->polishScheduled = false;
+ item->updatePolish();
+ }
+
+ if (recursionSafeguard == 0)
qWarning("QQuickWindow: possible QQuickItem::polish() loop");
updateFocusItemTransform();