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.7 6.5
Change-Id: If6784815bfa41e497cbc4e00bef51da3ded5f255
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io>
(cherry picked from commit 21e9875d62414306fde9738ab255e55f22d1c8ed)
This commit is contained in:
Mårten Nordheim 2024-08-09 15:44:08 +02:00
parent d8570cb1a8
commit 701263379a
2 changed files with 8 additions and 3 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

@ -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);