From cdb7e81572df726486fc0bdc648f732b797c7f84 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 18 Apr 2017 16:52:19 +0200 Subject: Fix UB in QLayout::childEvent We can't just static_cast a child to QLayout, because the child might not be a QLayout, and even if it was, we might be called from the QObject destructor so we would not be a layout anymore. Instead we can just qobject_cast the deleted object to a QLayout and remove it from the layout with removeItem. This would not take in account the case where we would be called because the QLayout gets destroyed, so we handle this case from ~QLayout by removing ourself from the parent. Note that the comment in ~QLayout was wrong, as the layout gets destroyed explicitly from ~QWidget, not from ~QObject. Change-Id: I49c6f17a76f207b9d750b6e5d987469498b96b31 Reviewed-by: Marc Mutz --- src/widgets/kernel/qlayout.cpp | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index f88ed350c7..129c12885a 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -641,21 +641,11 @@ void QLayout::childEvent(QChildEvent *e) if (!d->enabled) return; - if (e->type() == QEvent::ChildRemoved) { - QChildEvent *c = (QChildEvent*)e; - int i = 0; - - QLayoutItem *item; - while ((item = itemAt(i))) { - if (item == static_cast(c->child())) { - takeAt(i); - invalidate(); - break; - } else { - ++i; - } - } - } + if (e->type() != QEvent::ChildRemoved) + return; + + if (QLayout *childLayout = qobject_cast(e->child())) + removeItem(childLayout); } /*! @@ -766,13 +756,10 @@ QSize QLayout::totalMaximumSize() const QLayout::~QLayout() { Q_D(QLayout); - /* - This function may be called during the QObject destructor, - when the parent no longer is a QWidget. - */ - if (d->topLevel && parent() && parent()->isWidgetType() && - ((QWidget*)parent())->layout() == this) - ((QWidget*)parent())->d_func()->layout = 0; + if (d->topLevel && parent() && parent()->isWidgetType() && parentWidget()->layout() == this) + parentWidget()->d_func()->layout = 0; + else if (QLayout *parentLayout = qobject_cast(parent())) + parentLayout->removeItem(this); } -- cgit v1.2.3