Acknowledge QWidgetWindow::widget() may be null

We guard QWidgetWindow's widget with a QPointer to avoid
sending it events during destruction (which may result in
undefined behavior, since this originates from ~QObject and
we expect the object to behave as a QWidget). Therefore, we
need to harden all access to that widget since it can now
be null, specially during destruction.

As an example, QGestureManager may crash when we delete a
top-level widget. The crash stack trace is:

1  QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::data() const
2  QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::pointer qGetPtrHelper<QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>>(QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>> const&)
3  QWidget::d_func()
4  QGestureManager::filterEvent(QWidget *, QEvent *)  <-- the widget ptr is null
5  QGestureManager::filterEvent(QObject *, QEvent *)
6  QApplication::notify(QObject *, QEvent *)
7  QCoreApplication::notifyInternal2(QObject *, QEvent *)
8  QCoreApplication::sendEvent(QObject *, QEvent *)
9  QWindow::destroy()
10 QWidgetPrivate::deleteTLSysExtra()
11 QWidgetPrivate::deleteExtra()
12 QWidgetPrivate::~QWidgetPrivate()
13 QWidgetPrivate::~QWidgetPrivate()
14 QWidgetPrivate::~QWidgetPrivate()
15 QScopedPointerDeleter<QObjectData>::cleanup(QObjectData *)
16 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::~QScopedPointer()
17 QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData>>::~QScopedPointer()
18 QObject::~QObject()
19 QWidget::~QWidget()

Task-number: QTBUG-53103
Change-Id: I1bb32648270c4f7791f668b8f0b639ddb4235703
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
Gabriel de Dietrich 2016-04-29 16:32:42 -07:00
parent 6a84a51611
commit ce37467acf
3 changed files with 16 additions and 14 deletions

View File

@ -2249,10 +2249,10 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
QApplication::setActiveWindow(tlw); QApplication::setActiveWindow(tlw);
// QTBUG-37126, Active X controls may set the focus on native child widgets. // QTBUG-37126, Active X controls may set the focus on native child widgets.
if (wnd && tlw && wnd != tlw->windowHandle()) { if (wnd && tlw && wnd != tlw->windowHandle()) {
if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(wnd)) { if (QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(wnd))
if (widgetWindow->widget()->inherits("QAxHostWidget")) if (QWidget *widget = widgetWindow->widget())
widgetWindow->widget()->setFocus(Qt::ActiveWindowFocusReason); if (widget->inherits("QAxHostWidget"))
} widget->setFocus(Qt::ActiveWindowFocusReason);
} }
} }

View File

@ -545,7 +545,7 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event)
// filter method. // filter method.
QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver); QWidgetWindow *widgetWindow = qobject_cast<QWidgetWindow *>(receiver);
if (widgetWindow) if (widgetWindow && widgetWindow->widget())
return filterEvent(widgetWindow->widget(), event); return filterEvent(widgetWindow->widget(), event);
QGesture *state = qobject_cast<QGesture *>(receiver); QGesture *state = qobject_cast<QGesture *>(receiver);

View File

@ -87,7 +87,7 @@ QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
{ {
Q_Q(const QWidgetWindow); Q_Q(const QWidgetWindow);
const QWidget *widget = q->widget(); const QWidget *widget = q->widget();
if (!widget->isWindow() || !widget->hasHeightForWidth()) if (!widget || !widget->isWindow() || !widget->hasHeightForWidth())
return QRect(); return QRect();
const QSize oldSize = rect.size().toSize(); const QSize oldSize = rect.size().toSize();
const QSize newSize = QLayout::closestAcceptableSize(widget, oldSize); const QSize newSize = QLayout::closestAcceptableSize(widget, oldSize);
@ -142,16 +142,18 @@ QAccessibleInterface *QWidgetWindow::accessibleRoot() const
QObject *QWidgetWindow::focusObject() const QObject *QWidgetWindow::focusObject() const
{ {
QWidget *widget = m_widget->focusWidget(); QWidget *windowWidget = m_widget;
if (!windowWidget)
return Q_NULLPTR;
QWidget *widget = windowWidget->focusWidget();
if (!widget) if (!widget)
widget = m_widget; widget = windowWidget;
if (widget) { QObject *focusObj = QWidgetPrivate::get(widget)->focusObject();
QObject *focusObj = QWidgetPrivate::get(widget)->focusObject(); if (focusObj)
if (focusObj) return focusObj;
return focusObj;
}
return widget; return widget;
} }
@ -204,7 +206,7 @@ bool QWidgetWindow::event(QEvent *event)
#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_ACCESSIBILITY
QAccessible::State state; QAccessible::State state;
state.active = true; state.active = true;
QAccessibleStateChangeEvent ev(widget(), state); QAccessibleStateChangeEvent ev(m_widget, state);
QAccessible::updateAccessibility(&ev); QAccessible::updateAccessibility(&ev);
#endif #endif
return false; } return false; }