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 <lars@knoll.priv.no>
This commit is contained in:
Thiago Macieira 2023-04-03 15:03:04 -03:00
parent 59466abc08
commit 87103e04e9
2 changed files with 76 additions and 1 deletions

View File

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

View File

@ -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<int, int> 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<int, int> 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<int, int> 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<QString, int> hash;