From c4cab7199590cc6b1901334e8ff604cd876fccee Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 14 Sep 2011 14:07:06 +0100 Subject: Prevent crash when cache is changed on the fly Calling QNetworkAccessManager::setCache while there were requests being processed using the existing cache caused crashes due to deleting the old cache invalidating pointers to the cache data streams (QTemporaryFile in case of QNetworkDiskCache). Using pointer to deleted data caused a crash in some cases. It has undefined behaviour because the memory may have been overwritten or decommitted. To fix this, use the deleted signal to notify QNetworkReplyImpl that the cache has been destroyed. It then clears the pointer to the data stream and disables caching. This avoids the crash that previously happened when trying to write to the cache file. Task-number: QT-5252 Reviewed-by: Peter Hartmann --- src/network/access/qnetworkreplyimpl.cpp | 23 +++++++++++++++++++---- src/network/access/qnetworkreplyimpl_p.h | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 8a0a944..81cd548 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -446,6 +446,7 @@ bool QNetworkReplyImplPrivate::isCachingEnabled() const void QNetworkReplyImplPrivate::setCachingEnabled(bool enable) { + Q_Q(QNetworkReplyImpl); if (!enable && !cacheEnabled) return; // nothing to do if (enable && cacheEnabled) @@ -468,15 +469,27 @@ void QNetworkReplyImplPrivate::setCachingEnabled(bool enable) networkCache()->remove(url); cacheSaveDevice = 0; cacheEnabled = false; + QObject::disconnect(networkCache(), SIGNAL(destroyed()), q, SLOT(_q_cacheDestroyed())); } } +void QNetworkReplyImplPrivate::_q_cacheDestroyed() +{ + //destruction of cache invalidates cacheSaveDevice + cacheSaveDevice = 0; + cacheEnabled = false; +} + void QNetworkReplyImplPrivate::completeCacheSave() { - if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) { - networkCache()->remove(url); - } else if (cacheEnabled && cacheSaveDevice) { - networkCache()->insert(cacheSaveDevice); + Q_Q(QNetworkReplyImpl); + if (cacheEnabled) { + if (errorCode != QNetworkReplyImpl::NoError) { + networkCache()->remove(url); + } else if (cacheSaveDevice) { + networkCache()->insert(cacheSaveDevice); + } + QObject::disconnect(networkCache(), SIGNAL(destroyed()), q, SLOT(_q_cacheDestroyed())); } cacheSaveDevice = 0; cacheEnabled = false; @@ -536,6 +549,8 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice() networkCache()->remove(url); cacheSaveDevice = 0; cacheEnabled = false; + } else { + q->connect(networkCache(), SIGNAL(destroyed()), SLOT(_q_cacheDestroyed())); } } diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 31da297..0e4ff8f 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -103,6 +103,7 @@ public: Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed()) #endif + Q_PRIVATE_SLOT(d_func(), void _q_cacheDestroyed()) }; class QNetworkReplyImplPrivate: public QNetworkReplyPrivate @@ -139,6 +140,7 @@ public: void _q_networkSessionConnected(); void _q_networkSessionFailed(); #endif + void _q_cacheDestroyed(); void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData); -- cgit v0.12