Do not crash if resizing a layout that got its child destroyed

Normally updatePolish() would call ensureLayoutItemsUpdated(), but in
some cases the layout might be resized before the updatePolish() is
processed.
We therefore have to also call ensureLayoutItemsUpdated() from rearrange()

Fixes: QTBUG-111792
Change-Id: Iab24dafc26dfa86975348c92244034f7ff825e5f
Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
(cherry picked from commit 24f5695d35)
This commit is contained in:
Jan Arve Sæther 2023-03-10 13:52:42 +01:00
parent 4137fc0753
commit 8ff4f09b02
2 changed files with 42 additions and 1 deletions

View File

@ -457,6 +457,10 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size)
return;
}
// Should normally not be needed, but there might be an incoming window resize event that we
// will process before we process updatePolish()
ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive);
d->m_rearranging = true;
qCDebug(lcQuickLayouts) << objectName() << "QQuickGridLayoutBase::rearrange()" << size;
Qt::LayoutDirection visualDir = effectiveLayoutDirection();

View File

@ -1470,6 +1470,43 @@ Item {
verify(!BindingLoopDetector.bindingLoopDetected, "Detected binding loop")
BindingLoopDetector.reset()
}
}
//---------------------------
// QTBUG-111792
Component {
id: rowlayoutCrashes_Component
RowLayout {
spacing: 5
Rectangle {
color: "red"
implicitWidth: 10
implicitHeight: 10
}
Rectangle {
color: "green"
implicitWidth: 10
implicitHeight: 10
}
}
}
function test_dontCrashAfterDestroyingChildren_data() {
return [
{ tag: "setWidth", func: function (layout) { layout.width = 42 } },
{ tag: "setHeight", func: function (layout) { layout.height = 42 } },
{ tag: "getImplicitWidth", func: function (layout) { let x = layout.implicitWidth } },
{ tag: "getImplicitHeight", func: function (layout) { let x = layout.implicitHeight } },
]
}
function test_dontCrashAfterDestroyingChildren(data) {
var layout = createTemporaryObject(rowlayoutCrashes_Component, container)
waitForRendering(layout)
compare(layout.implicitWidth, 25)
layout.children[0].destroy() // deleteLater()
wait(0) // process the scheduled delete and actually invoke the dtor
data.func(layout) // call a function that might ultimately access the deleted item (but shouldn't)
}
}
}