diff options
| author | Ivan Solovev <ivan.solovev@qt.io> | 2022-03-30 17:09:32 +0200 |
|---|---|---|
| committer | Ivan Solovev <ivan.solovev@qt.io> | 2022-04-06 16:46:59 +0200 |
| commit | d11941db41f00525f907417bbcd6ac5ee30d8485 (patch) | |
| tree | ffcc5ad3b6d82252ae0128272afe63af1b30db73 | |
| parent | 87098106d0efc7c6e0b7eb01ffa72f27b47b85d5 (diff) | |
Q[Multi]Hash::reserve(): do nothing if desired size is less than current
Calling Q[Multi]Hash::reserve(n) when n is much smaller than the
current amount of elements in the hash, could result in an infinite
loop, because at some point the algorithm could not find a free bucket
for the element.
Fixing it by returning early if the new desired capacity is less than
current.
Fixes: QTBUG-102067
Pick-to: 6.3 6.2
Change-Id: I38ef0b2168c4e2a317eedf91b2155b1fdffb1c27
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
| -rw-r--r-- | src/corelib/tools/qhash.h | 6 | ||||
| -rw-r--r-- | tests/auto/corelib/tools/qhash/tst_qhash.cpp | 31 |
2 files changed, 37 insertions, 0 deletions
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 73a0225106d..6a545988d43 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -944,6 +944,9 @@ public: inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; } void reserve(qsizetype size) { + // reserve(0) is used in squeeze() + if (size && (this->capacity() >= size)) + return; if (isDetached()) d->rehash(size); else @@ -1507,6 +1510,9 @@ public: inline qsizetype capacity() const noexcept { return d ? qsizetype(d->numBuckets >> 1) : 0; } void reserve(qsizetype size) { + // reserve(0) is used in squeeze() + if (size && (this->capacity() >= size)) + return; if (isDetached()) d->rehash(size); else diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index fac4ac7007c..6f59fe44362 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -98,6 +98,7 @@ private slots: void fineTuningInEmptyHash(); void reserveShared(); + void reserveLessThanCurrentAmount(); void QTBUG98265(); @@ -2667,6 +2668,36 @@ void tst_QHash::reserveShared() QCOMPARE(hash.capacity(), oldCap); } +void tst_QHash::reserveLessThanCurrentAmount() +{ + { + QHash<int, int> hash; + for (int i = 0; i < 1000; ++i) + hash.insert(i, i * 10); + + // This used to hang in an infinite loop: QTBUG-102067 + hash.reserve(1); + + // Make sure that hash still has all elements + for (int i = 0; i < 1000; ++i) + QCOMPARE(hash.value(i), i * 10); + } + { + QMultiHash<int, int> hash; + for (int i = 0; i < 1000; ++i) { + hash.insert(i, i * 10); + hash.insert(i, i * 10 + 1); + } + + // This used to hang in infinite loop: QTBUG-102067 + hash.reserve(1); + + // Make sure that hash still has all elements + for (int i = 0; i < 1000; ++i) + QCOMPARE(hash.values(i), QList<int>() << i * 10 + 1 << i * 10); + } +} + void tst_QHash::QTBUG98265() { QMultiHash<QUuid, QByteArray> a; |
