QFreeList: return timer IDs with the serial included

When a timer gets unregistered there is a chance that a new timer is
registered again immediately and gets the same ID.
On Windows this is a problem because there may be WM_TIMER messages
remaining in the native event loop that have not been processed.
This may result in unexpected timeouts for newly started timers.

By not masking away the serial/generation from the ID we generate
we will no longer return the same ID that was just freed.

While QFreeList mostly was prepared to be used in this way, one function
was not, and the tests were written with the assumption that the serial
was masked out. So this patch also addresses that.

Fixes: QTBUG-124496
Pick-to: 6.8 6.7 6.5
Change-Id: If6784815bfa41e497cbc4e00bef51da3ded5f255
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io>
This commit is contained in:
Mårten Nordheim 2024-08-09 15:44:08 +02:00
parent ab6f116009
commit 21e9875d62
3 changed files with 8 additions and 4 deletions

View File

@ -118,6 +118,7 @@ class QFreeList
// return which block the index \a x falls in, and modify \a x to be the index into that block
static inline int blockfor(int &x)
{
x = x & ConstantsType::IndexMask;
for (int i = 0; i < ConstantsType::BlockCount; ++i) {
int size = ConstantsType::Sizes[i];
if (x < size)
@ -223,7 +224,7 @@ inline int QFreeList<T, ConstantsType>::next()
// id & ConstantsType::IndexMask,
// newid & ConstantsType::IndexMask,
// (newid & ~ConstantsType::IndexMask) >> 24);
return id & ConstantsType::IndexMask;
return id;
}
template <typename T, typename ConstantsType>

View File

@ -664,7 +664,6 @@ void tst_QChronoTimer::newTimerFiresTooSoon()
listener.killTimer(timerId);
// Assert
QEXPECT_FAIL("", "QTBUG-124496 - QObject::timerEvent may be called before the timer elapsed", Continue);
QVERIFY(!listener.m_timerElapsed);
#endif
}

View File

@ -36,9 +36,12 @@ void tst_QFreeList::basicTest()
voidFreeList.at(two);
voidFreeList.release(one);
int next = voidFreeList.next();
QCOMPARE(next, 1);
QCOMPARE_NE(next, 1); // With generation counter
QCOMPARE(next & QFreeListDefaultConstants::IndexMask, 1);
voidFreeList[next];
voidFreeList.at(next);
voidFreeList.release(next);
QCOMPARE(voidFreeList.next() & QFreeListDefaultConstants::IndexMask, 1);
}
{
@ -57,7 +60,8 @@ void tst_QFreeList::basicTest()
QCOMPARE(intFreeList.at(two), two);
intFreeList.release(one);
int next = intFreeList.next();
QCOMPARE(next, 1);
QCOMPARE_NE(next, 1); // With generation counter
QCOMPARE(next & QFreeListDefaultConstants::IndexMask, 1);
QCOMPARE(intFreeList.at(next), one);
intFreeList[next] = -one;
QCOMPARE(intFreeList.at(next), -one);