Fix QNetworkAccessCache after QHash stability semantics change

The data structure relies on stable nodes in QHash, something that
is not guaranteed in Qt 6 anymore.

Change-Id: I9077ed404ee922893099f5eaae76d2dcea414090
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Lars Knoll 2020-03-13 12:44:31 +01:00
parent e87768a880
commit fed4d6d78d
2 changed files with 42 additions and 43 deletions

View File

@ -121,8 +121,9 @@ void QNetworkAccessCache::clear()
NodeHash::Iterator it = hashCopy.begin(); NodeHash::Iterator it = hashCopy.begin();
NodeHash::Iterator end = hashCopy.end(); NodeHash::Iterator end = hashCopy.end();
for ( ; it != end; ++it) { for ( ; it != end; ++it) {
it->object->key.clear(); (*it)->object->key.clear();
it->object->dispose(); (*it)->object->dispose();
delete (*it);
} }
// now delete: // now delete:
@ -139,11 +140,10 @@ void QNetworkAccessCache::clear()
*/ */
void QNetworkAccessCache::linkEntry(const QByteArray &key) void QNetworkAccessCache::linkEntry(const QByteArray &key)
{ {
NodeHash::Iterator it = hash.find(key); Node * const node = hash.value(key);
if (it == hash.end()) if (!node)
return; return;
Node *const node = &it.value();
Q_ASSERT(node != oldest && node != newest); Q_ASSERT(node != oldest && node != newest);
Q_ASSERT(node->older == nullptr && node->newer == nullptr); Q_ASSERT(node->older == nullptr && node->newer == nullptr);
Q_ASSERT(node->useCount == 0); Q_ASSERT(node->useCount == 0);
@ -168,12 +168,10 @@ void QNetworkAccessCache::linkEntry(const QByteArray &key)
*/ */
bool QNetworkAccessCache::unlinkEntry(const QByteArray &key) bool QNetworkAccessCache::unlinkEntry(const QByteArray &key)
{ {
NodeHash::Iterator it = hash.find(key); Node * const node = hash.value(key);
if (it == hash.end()) if (!node)
return false; return false;
Node *const node = &it.value();
bool wasOldest = false; bool wasOldest = false;
if (node == oldest) { if (node == oldest) {
oldest = node->newer; oldest = node->newer;
@ -230,6 +228,7 @@ void QNetworkAccessCache::timerEvent(QTimerEvent *)
oldest->object->dispose(); oldest->object->dispose();
hash.remove(oldest->key); // oldest gets deleted hash.remove(oldest->key); // oldest gets deleted
delete oldest;
oldest = next; oldest = next;
} }
@ -249,16 +248,20 @@ void QNetworkAccessCache::addEntry(const QByteArray &key, CacheableObject *entry
if (unlinkEntry(key)) if (unlinkEntry(key))
updateTimer(); updateTimer();
Node &node = hash[key]; // create the entry in the hash if it didn't exist Node *node = hash.value(key);
if (node.useCount) if (!node) {
qWarning("QNetworkAccessCache::addEntry: overriding active cache entry '%s'", node = new Node;
key.constData()); hash.insert(key, node);
if (node.object) }
node.object->dispose();
node.object = entry; if (node->useCount)
node.object->key = key; qWarning("QNetworkAccessCache::addEntry: overriding active cache entry '%s'", key.constData());
node.key = key; if (node->object)
node.useCount = 1; node->object->dispose();
node->object = entry;
node->object->key = key;
node->key = key;
node->useCount = 1;
} }
bool QNetworkAccessCache::hasEntry(const QByteArray &key) const bool QNetworkAccessCache::hasEntry(const QByteArray &key) const
@ -268,11 +271,9 @@ bool QNetworkAccessCache::hasEntry(const QByteArray &key) const
bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, const char *member) bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, const char *member)
{ {
NodeHash::Iterator it = hash.find(key); Node *node = hash.value(key);
if (it == hash.end()) if (!node)
return false; // no such entry return false;
Node *node = &it.value();
if (node->useCount > 0 && !node->object->shareable) { if (node->useCount > 0 && !node->object->shareable) {
// object is not shareable and is in use // object is not shareable and is in use
@ -294,13 +295,14 @@ bool QNetworkAccessCache::requestEntry(const QByteArray &key, QObject *target, c
QNetworkAccessCache::CacheableObject *QNetworkAccessCache::requestEntryNow(const QByteArray &key) QNetworkAccessCache::CacheableObject *QNetworkAccessCache::requestEntryNow(const QByteArray &key)
{ {
NodeHash::Iterator it = hash.find(key); Node *node = hash.value(key);
if (it == hash.end()) if (!node)
return nullptr; return nullptr;
if (it->useCount > 0) {
if (it->object->shareable) { if (node->useCount > 0) {
++it->useCount; if (node->object->shareable) {
return it->object; ++node->useCount;
return node->object;
} }
// object in use and not shareable // object in use and not shareable
@ -309,23 +311,21 @@ QNetworkAccessCache::CacheableObject *QNetworkAccessCache::requestEntryNow(const
// entry not in use, let the caller have it // entry not in use, let the caller have it
bool wasOldest = unlinkEntry(key); bool wasOldest = unlinkEntry(key);
++it->useCount; ++node->useCount;
if (wasOldest) if (wasOldest)
updateTimer(); updateTimer();
return it->object; return node->object;
} }
void QNetworkAccessCache::releaseEntry(const QByteArray &key) void QNetworkAccessCache::releaseEntry(const QByteArray &key)
{ {
NodeHash::Iterator it = hash.find(key); Node *node = hash.value(key);
if (it == hash.end()) { if (!node) {
qWarning("QNetworkAccessCache::releaseEntry: trying to release key '%s' that is not in cache", qWarning("QNetworkAccessCache::releaseEntry: trying to release key '%s' that is not in cache", key.constData());
key.constData());
return; return;
} }
Node *node = &it.value();
Q_ASSERT(node->useCount > 0); Q_ASSERT(node->useCount > 0);
// are there other objects waiting? // are there other objects waiting?
@ -356,14 +356,12 @@ void QNetworkAccessCache::releaseEntry(const QByteArray &key)
void QNetworkAccessCache::removeEntry(const QByteArray &key) void QNetworkAccessCache::removeEntry(const QByteArray &key)
{ {
NodeHash::Iterator it = hash.find(key); Node *node = hash.value(key);
if (it == hash.end()) { if (!node) {
qWarning("QNetworkAccessCache::removeEntry: trying to remove key '%s' that is not in cache", qWarning("QNetworkAccessCache::removeEntry: trying to remove key '%s' that is not in cache", key.constData());
key.constData());
return; return;
} }
Node *node = &it.value();
if (unlinkEntry(key)) if (unlinkEntry(key))
updateTimer(); updateTimer();
if (node->useCount > 1) if (node->useCount > 1)
@ -372,6 +370,7 @@ void QNetworkAccessCache::removeEntry(const QByteArray &key)
node->object->key.clear(); node->object->key.clear();
hash.remove(node->key); hash.remove(node->key);
delete node;
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -71,7 +71,7 @@ class QNetworkAccessCache: public QObject
Q_OBJECT Q_OBJECT
public: public:
struct Node; struct Node;
typedef QHash<QByteArray, Node> NodeHash; typedef QHash<QByteArray, Node *> NodeHash;
class CacheableObject class CacheableObject
{ {