From ce37467acf34edf1380f896a0942b616dc4cbead Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 29 Apr 2016 16:32:42 -0700 Subject: [PATCH] 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>::data() const 2 QScopedPointer>::pointer qGetPtrHelper>>(QScopedPointer> 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::cleanup(QObjectData *) 16 QScopedPointer>::~QScopedPointer() 17 QScopedPointer>::~QScopedPointer() 18 QObject::~QObject() 19 QWidget::~QWidget() Task-number: QTBUG-53103 Change-Id: I1bb32648270c4f7791f668b8f0b639ddb4235703 Reviewed-by: Shawn Rutledge Reviewed-by: Marc Mutz --- src/widgets/kernel/qapplication.cpp | 8 ++++---- src/widgets/kernel/qgesturemanager.cpp | 2 +- src/widgets/kernel/qwidgetwindow.cpp | 20 +++++++++++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index a459a57482..fcc195f601 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2249,10 +2249,10 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous) QApplication::setActiveWindow(tlw); // QTBUG-37126, Active X controls may set the focus on native child widgets. if (wnd && tlw && wnd != tlw->windowHandle()) { - if (QWidgetWindow *widgetWindow = qobject_cast(wnd)) { - if (widgetWindow->widget()->inherits("QAxHostWidget")) - widgetWindow->widget()->setFocus(Qt::ActiveWindowFocusReason); - } + if (QWidgetWindow *widgetWindow = qobject_cast(wnd)) + if (QWidget *widget = widgetWindow->widget()) + if (widget->inherits("QAxHostWidget")) + widget->setFocus(Qt::ActiveWindowFocusReason); } } diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 967ef6b40c..89ed6922b5 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -545,7 +545,7 @@ bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) // filter method. QWidgetWindow *widgetWindow = qobject_cast(receiver); - if (widgetWindow) + if (widgetWindow && widgetWindow->widget()) return filterEvent(widgetWindow->widget(), event); QGesture *state = qobject_cast(receiver); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index ec2618e501..5290d79d9e 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -87,7 +87,7 @@ QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const { Q_Q(const QWidgetWindow); const QWidget *widget = q->widget(); - if (!widget->isWindow() || !widget->hasHeightForWidth()) + if (!widget || !widget->isWindow() || !widget->hasHeightForWidth()) return QRect(); const QSize oldSize = rect.size().toSize(); const QSize newSize = QLayout::closestAcceptableSize(widget, oldSize); @@ -142,16 +142,18 @@ QAccessibleInterface *QWidgetWindow::accessibleRoot() 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) - widget = m_widget; + widget = windowWidget; - if (widget) { - QObject *focusObj = QWidgetPrivate::get(widget)->focusObject(); - if (focusObj) - return focusObj; - } + QObject *focusObj = QWidgetPrivate::get(widget)->focusObject(); + if (focusObj) + return focusObj; return widget; } @@ -204,7 +206,7 @@ bool QWidgetWindow::event(QEvent *event) #ifndef QT_NO_ACCESSIBILITY QAccessible::State state; state.active = true; - QAccessibleStateChangeEvent ev(widget(), state); + QAccessibleStateChangeEvent ev(m_widget, state); QAccessible::updateAccessibility(&ev); #endif return false; }