From 87103e04e9c34630bd51ae5f8e7550033976c6bf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 3 Apr 2023 15:03:04 -0300 Subject: [PATCH] QMultiHash: fix missing update to m_size QMultiHash has access to two sizes: one of them is shared with QHash, stored in QHashPrivate::Data::size, which counts keys; the other, which is what our public size() function returns, is stored in QMultiHash::m_size and counts plain (key,value) entries. We forgot to update it in the non-const operator[] that created a node. I've reviewed the rest of the code and can't find any more places where the item count may be changed and m_size isn't updated. [ChangeLog][QtCore][QMultiHash] Fixed a bug that caused an element that was created by operator[] to not be counted, resulting in a hash map with an incorrect element count and which could cause an assertion failure depending on how the hash was later mutated. Fixes: QTBUG-112534 Pick-to: 6.2 6.4 6.5 Change-Id: Idd5e1bb52be047d7b4fffffd17527ec274e1d99e Reviewed-by: Lars Knoll --- src/corelib/tools/qhash.h | 4 +- tests/auto/corelib/tools/qhash/tst_qhash.cpp | 73 ++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 09766859a9..040feb080b 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -1632,8 +1632,10 @@ public: detach(); auto result = d->findOrInsert(key); Q_ASSERT(!result.it.atEnd()); - if (!result.initialized) + if (!result.initialized) { Node::createInPlace(result.it.node(), key, T()); + ++m_size; + } return result.it.node()->value->value; } diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 50b1248d91..c906924b2b 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -42,6 +42,7 @@ private slots: void qmultihash_qhash_rvalue_ref_ctor(); void qmultihash_qhash_rvalue_ref_unite(); void qmultihashUnite(); + void qmultihashSize(); void compare(); void compare2(); @@ -2051,6 +2052,78 @@ void tst_QHash::qmultihashUnite() } } +void tst_QHash::qmultihashSize() +{ + // QMultiHash has an extra m_size member that counts the number of values, + // while d->size (shared with QHash) counts the number of distinct keys. + { + QMultiHash hash; + QCOMPARE(hash.size(), 0); + QVERIFY(hash.isEmpty()); + + hash.insert(0, 42); + QCOMPARE(hash.size(), 1); + QVERIFY(!hash.isEmpty()); + + hash.insert(0, 42); + QCOMPARE(hash.size(), 2); + QVERIFY(!hash.isEmpty()); + + hash.emplace(0, 42); + QCOMPARE(hash.size(), 3); + QVERIFY(!hash.isEmpty()); + + QCOMPARE(hash.take(0), 42); + QCOMPARE(hash.size(), 2); + QVERIFY(!hash.isEmpty()); + + QCOMPARE(hash.remove(0), 2); + QCOMPARE(hash.size(), 0); + QVERIFY(hash.isEmpty()); + } + + { + QMultiHash hash; + hash.emplace(0, 0); + hash.emplace(0, 0); + QCOMPARE(hash.size(), 2); + QVERIFY(!hash.isEmpty()); + + hash.emplace(0, 1); + QCOMPARE(hash.size(), 3); + QVERIFY(!hash.isEmpty()); + + QCOMPARE(hash.remove(0, 0), 2); + QCOMPARE(hash.size(), 1); + QVERIFY(!hash.isEmpty()); + + hash.remove(0); + QCOMPARE(hash.size(), 0); + QVERIFY(hash.isEmpty()); + } + + { + QMultiHash hash; + + hash[0] = 0; + QCOMPARE(hash.size(), 1); + QVERIFY(!hash.isEmpty()); + + hash.replace(0, 1); + QCOMPARE(hash.size(), 1); + QVERIFY(!hash.isEmpty()); + + hash.insert(0, 1); + hash.erase(hash.cbegin()); + QCOMPARE(hash.size(), 1); + QVERIFY(!hash.isEmpty()); + + hash.erase(hash.cbegin()); + QCOMPARE(hash.size(), 0); + QVERIFY(hash.isEmpty()); + } +} + void tst_QHash::keys_values_uniqueKeys() { QMultiHash hash;