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 <marc.mutz@kdab.com>
This commit is contained in:
Olivier Goffart 2017-04-18 16:52:19 +02:00 committed by Olivier Goffart (Woboq GmbH)
parent f368cd8868
commit cdb7e81572

View File

@ -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;
if (e->type() != QEvent::ChildRemoved)
return;
QLayoutItem *item;
while ((item = itemAt(i))) {
if (item == static_cast<QLayout*>(c->child())) {
takeAt(i);
invalidate();
break;
} else {
++i;
}
}
}
if (QLayout *childLayout = qobject_cast<QLayout *>(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<QLayout *>(parent()))
parentLayout->removeItem(this);
}