Drag'n'Drop: fix crash when widgets are destroyed during event handling

Widgets might be destroyed when handling a dragMoveEvent, in which case
the following code will operate on dangling pointers or null pointers.
Use a QPointer to watch for the original event receiver to disappear,
and add the necessary checks for the objects we deliver events to being
null.

Change-Id: I4ca2f182540ae21113f4bea4e5c569e983cc58bf
Fixes: QTBUG-78907
Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
This commit is contained in:
Volker Hilsheimer 2019-10-08 10:56:44 +02:00 committed by Shawn Rutledge
parent 9845c06d1f
commit 3dbc7596a3

View File

@ -885,7 +885,7 @@ void QWidgetWindow::handleDragEnterEvent(QDragEnterEvent *event, QWidget *widget
void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event) void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
{ {
auto *widget = findDnDTarget(m_widget, event->pos()); QPointer<QWidget> widget = findDnDTarget(m_widget, event->pos());
if (!widget) { if (!widget) {
event->ignore(); event->ignore();
if (m_dragTarget) { // Send DragLeave to previous if (m_dragTarget) { // Send DragLeave to previous
@ -908,14 +908,18 @@ void QWidgetWindow::handleDragMoveEvent(QDragMoveEvent *event)
QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event); QGuiApplication::forwardEvent(m_dragTarget, &leaveEvent, event);
m_dragTarget = nullptr; m_dragTarget = nullptr;
} }
// Send DragEnter to new widget. // widget might have been deleted when handling the leaveEvent
handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget); if (widget) {
// Handling 'DragEnter' should suffice for the application. // Send DragEnter to new widget.
translated.setDropAction(event->dropAction()); handleDragEnterEvent(static_cast<QDragEnterEvent*>(event), widget);
translated.setAccepted(event->isAccepted()); // Handling 'DragEnter' should suffice for the application.
// The drag enter event is always immediately followed by a drag move event, translated.setDropAction(event->dropAction());
// see QDragEnterEvent documentation. translated.setAccepted(event->isAccepted());
QGuiApplication::forwardEvent(m_dragTarget, &translated, event); // The drag enter event is always immediately followed by a drag move event,
// see QDragEnterEvent documentation.
if (m_dragTarget)
QGuiApplication::forwardEvent(m_dragTarget, &translated, event);
}
} }
event->setAccepted(translated.isAccepted()); event->setAccepted(translated.isAccepted());
event->setDropAction(translated.dropAction()); event->setDropAction(translated.dropAction());