winrt: Fix potential memory corruption

The timerInfo list might get accessed concurrently and cause references
to become dangling. Hence, we need to protect usages with a mutex.
According to tests/benchmark there is no impact on performance.

Task-number: QTBUG-56756
Change-Id: I4bdffccff70d2dca99f4a39defad438afe571ada
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
bb10
Maurice Kalinowski 2016-10-31 12:57:38 +01:00
parent c972c452e2
commit fe51dbac3d
1 changed files with 23 additions and 6 deletions

View File

@ -36,6 +36,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QHash>
#include <QtCore/QMutex>
#include <QtCore/qfunctions_winrt.h>
#include <private/qabstracteventdispatcher_p.h>
#include <private/qcoreapplication_p.h>
@ -100,6 +101,7 @@ public:
private:
QHash<int, QObject *> timerIdToObject;
QVector<WinRTTimerInfo> timerInfos;
mutable QMutex timerInfoLock;
QHash<HANDLE, int> timerHandleToId;
QHash<int, HANDLE> timerIdToHandle;
QHash<int, HANDLE> timerIdToCancelHandle;
@ -116,6 +118,7 @@ private:
timerIdToObject.insert(id, obj);
const quint64 targetTime = qt_msectime() + interval;
const WinRTTimerInfo info(id, interval, type, obj, targetTime);
QMutexLocker locker(&timerInfoLock);
if (id >= timerInfos.size())
timerInfos.resize(id + 1);
timerInfos[id] = info;
@ -124,6 +127,7 @@ private:
bool removeTimer(int id)
{
QMutexLocker locker(&timerInfoLock);
if (id >= timerInfos.size())
return false;
@ -247,14 +251,18 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags)
if (timerId == INTERRUPT_HANDLE)
break;
WinRTTimerInfo &info = d->timerInfos[timerId];
Q_ASSERT(info.timerId != INVALID_TIMER_ID);
{
QMutexLocker locker(&d->timerInfoLock);
QCoreApplication::postEvent(this, new QTimerEvent(timerId));
WinRTTimerInfo &info = d->timerInfos[timerId];
Q_ASSERT(info.timerId != INVALID_TIMER_ID);
// Update timer's targetTime
const quint64 targetTime = qt_msectime() + info.interval;
info.targetTime = targetTime;
QCoreApplication::postEvent(this, new QTimerEvent(timerId));
// Update timer's targetTime
const quint64 targetTime = qt_msectime() + info.interval;
info.targetTime = targetTime;
}
waitResult = WaitForMultipleObjectsEx(timerHandles.count(), timerHandles.constData(), FALSE, 0, TRUE);
}
emit awake();
@ -421,6 +429,7 @@ QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherWinRT::registeredTime
}
Q_D(const QEventDispatcherWinRT);
QMutexLocker locker(&d->timerInfoLock);
QList<TimerInfo> timerInfos;
foreach (const WinRTTimerInfo &info, d->timerInfos) {
if (info.object == object && info.timerId != INVALID_TIMER_ID)
@ -452,6 +461,7 @@ int QEventDispatcherWinRT::remainingTime(int timerId)
}
Q_D(QEventDispatcherWinRT);
QMutexLocker locker(&d->timerInfoLock);
const WinRTTimerInfo timerInfo = d->timerInfos.at(timerId);
if (timerInfo.timerId == INVALID_TIMER_ID) {
#ifndef QT_NO_DEBUG
@ -500,6 +510,9 @@ bool QEventDispatcherWinRT::event(QEvent *e)
case QEvent::Timer: {
QTimerEvent *timerEvent = static_cast<QTimerEvent *>(e);
const int id = timerEvent->timerId();
QMutexLocker locker(&d->timerInfoLock);
Q_ASSERT(id < d->timerInfos.size());
WinRTTimerInfo &info = d->timerInfos[id];
Q_ASSERT(info.timerId != INVALID_TIMER_ID);
@ -508,9 +521,13 @@ bool QEventDispatcherWinRT::event(QEvent *e)
break;
info.inEvent = true;
locker.unlock();
QTimerEvent te(id);
QCoreApplication::sendEvent(d->timerIdToObject.value(id), &te);
locker.relock();
// The timer might have been removed in the meanwhile
if (id >= d->timerInfos.size())
break;