From 21e9875d62414306fde9738ab255e55f22d1c8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 9 Aug 2024 15:44:08 +0200 Subject: [PATCH] QFreeList: return timer IDs with the serial included MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Jøger Hansegård --- src/corelib/tools/qfreelist_p.h | 3 ++- .../auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp | 1 - tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h index 6bbde5b4b66..5c12332aa4a 100644 --- a/src/corelib/tools/qfreelist_p.h +++ b/src/corelib/tools/qfreelist_p.h @@ -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::next() // id & ConstantsType::IndexMask, // newid & ConstantsType::IndexMask, // (newid & ~ConstantsType::IndexMask) >> 24); - return id & ConstantsType::IndexMask; + return id; } template diff --git a/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp b/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp index 18b2c31331d..2fb29a2e874 100644 --- a/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp +++ b/tests/auto/corelib/kernel/qchronotimer/tst_qchronotimer.cpp @@ -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 } diff --git a/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp b/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp index a45fa6d400d..aabe261451c 100644 --- a/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp +++ b/tests/auto/corelib/tools/qfreelist/tst_qfreelist.cpp @@ -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);