QEventDispatcherWin32: unregister event notifiers on close

When QEventDispatcherWin32::closingDown() is called,
threadData->eventDispatcher is already nullptr and the application
will no longer process the events.

Thus, just as it works for socket notifiers and timers, it makes sense
to disable all active event notifiers at this point. Otherwise, it
seems possible that an object in signalled state can provoke a data
race in the notifier's callback on 'edp' pointer, if
QWin32EventDispatcher destructor is running simultaneously.

Task-number: QTBUG-64152
Task-number: QTBUG-70214
Change-Id: I6e77f3eeca1b0ea639021e73b86798cba0200ebf
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Alex Trotsenko 2019-11-16 16:02:29 +02:00
parent b711ee2555
commit 23785face5
3 changed files with 10 additions and 4 deletions

View File

@ -884,7 +884,11 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
return;
}
#endif
doUnregisterEventNotifier(notifier);
}
void QEventDispatcherWin32::doUnregisterEventNotifier(QWinEventNotifier *notifier)
{
Q_D(QEventDispatcherWin32);
int i = d->winEventNotifierList.indexOf(notifier);
@ -996,6 +1000,10 @@ void QEventDispatcherWin32::closingDown()
doUnregisterSocketNotifier((*(d->sn_except.begin()))->obj);
Q_ASSERT(d->active_fd.isEmpty());
// clean up any eventnotifiers
while (!d->winEventNotifierList.isEmpty())
doUnregisterEventNotifier(d->winEventNotifierList.first());
// clean up any timers
for (int i = 0; i < d->timerVec.count(); ++i)
d->unregisterTimer(d->timerVec.at(i));

View File

@ -110,6 +110,7 @@ protected:
QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0);
virtual void sendPostedEvents();
void doUnregisterSocketNotifier(QSocketNotifier *notifier);
void doUnregisterEventNotifier(QWinEventNotifier *notifier);
private:
friend LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);

View File

@ -198,11 +198,8 @@ void QWinEventNotifier::setEnabled(bool enable)
d->enabled = enable;
QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
if (!eventDispatcher) { // perhaps application is shutting down
if (!enable && d->waitHandle != nullptr)
d->unregisterWaitObject();
if (!eventDispatcher) // perhaps application is shutting down
return;
}
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread");
return;