summaryrefslogtreecommitdiffstats
path: root/src/gui/image
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2018-12-17 11:12:50 +0100
committerEirik Aavitsland <eirik.aavitsland@qt.io>2019-07-10 12:43:23 +0200
commit2d597c0e1a32dda3f4d2f1c941b8a0d2a4be4735 (patch)
treee2b39f01b68e0ce92d83420a1aeeb2974936fcaf /src/gui/image
parent89aa6e780a28b2c6dc9f57d14afd2c49b743f472 (diff)
QPixmapCache: guard against usage from non-main threads
Depending on the active QPA plugin, QPixmaps may now be created and used also in non-main threads. But QPixmapCache is not designed to be used from such threads, so add guards to ignore such access attempts, both from application code and from Qt library code. Such unsafe access would often cause a cryptical "~QObject: Timers cannot be stopped from another thread" warning; that also disappears with this fix. [ChangeLog][QtGui][QPixmapCache] Ignore unsafe access from non-main threads Task-number: QTBUG-76694 Task-number: QTBUG-72523 Change-Id: Ia2db37e528aec08bfb48808630bdf5e543689039 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/gui/image')
-rw-r--r--src/gui/image/qpixmapcache.cpp33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp
index 3d1652f68b..e01a245cff 100644
--- a/src/gui/image/qpixmapcache.cpp
+++ b/src/gui/image/qpixmapcache.cpp
@@ -42,6 +42,8 @@
#include "qobject.h"
#include "qdebug.h"
#include "qpixmapcache_p.h"
+#include "qthread.h"
+#include "qcoreapplication.h"
QT_BEGIN_NAMESPACE
@@ -83,6 +85,9 @@ QT_BEGIN_NAMESPACE
with QPixmapCache} explains how to use QPixmapCache to speed up
applications by caching the results of painting.
+ \note QPixmapCache is only usable from the application's main thread.
+ Access from other threads will be ignored and return failure.
+
\sa QCache, QPixmap
*/
@@ -98,6 +103,14 @@ static inline int cost(const QPixmap &pixmap)
return static_cast<int>(qBound(1LL, costKb, costMax));
}
+static inline bool qt_pixmapcache_thread_test()
+{
+ if (Q_LIKELY(QCoreApplication::instance() && QThread::currentThread() == QCoreApplication::instance()->thread()))
+ return true;
+
+ return false;
+}
+
/*!
\class QPixmapCache::Key
\brief The QPixmapCache::Key class can be used for efficient access
@@ -487,6 +500,8 @@ QPixmapCacheEntry::~QPixmapCacheEntry()
QPixmap *QPixmapCache::find(const QString &key)
{
+ if (!qt_pixmapcache_thread_test())
+ return nullptr;
return pm_cache()->object(key);
}
@@ -515,6 +530,8 @@ bool QPixmapCache::find(const QString &key, QPixmap& pixmap)
bool QPixmapCache::find(const QString &key, QPixmap* pixmap)
{
+ if (!qt_pixmapcache_thread_test())
+ return false;
QPixmap *ptr = pm_cache()->object(key);
if (ptr && pixmap)
*pixmap = *ptr;
@@ -532,6 +549,8 @@ bool QPixmapCache::find(const QString &key, QPixmap* pixmap)
*/
bool QPixmapCache::find(const Key &key, QPixmap* pixmap)
{
+ if (!qt_pixmapcache_thread_test())
+ return false;
//The key is not valid anymore, a flush happened before probably
if (!key.d || !key.d->isValid)
return false;
@@ -563,6 +582,8 @@ bool QPixmapCache::find(const Key &key, QPixmap* pixmap)
bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap)
{
+ if (!qt_pixmapcache_thread_test())
+ return false;
return pm_cache()->insert(key, pixmap, cost(pixmap));
}
@@ -583,6 +604,8 @@ bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap)
*/
QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap)
{
+ if (!qt_pixmapcache_thread_test())
+ return QPixmapCache::Key();
return pm_cache()->insert(pixmap, cost(pixmap));
}
@@ -597,6 +620,8 @@ QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap)
*/
bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
{
+ if (!qt_pixmapcache_thread_test())
+ return false;
//The key is not valid anymore, a flush happened before probably
if (!key.d || !key.d->isValid)
return false;
@@ -626,6 +651,8 @@ int QPixmapCache::cacheLimit()
void QPixmapCache::setCacheLimit(int n)
{
+ if (!qt_pixmapcache_thread_test())
+ return;
pm_cache()->setMaxCost(n);
}
@@ -634,6 +661,8 @@ void QPixmapCache::setCacheLimit(int n)
*/
void QPixmapCache::remove(const QString &key)
{
+ if (!qt_pixmapcache_thread_test())
+ return;
pm_cache()->remove(key);
}
@@ -645,6 +674,8 @@ void QPixmapCache::remove(const QString &key)
*/
void QPixmapCache::remove(const Key &key)
{
+ if (!qt_pixmapcache_thread_test())
+ return;
//The key is not valid anymore, a flush happened before probably
if (!key.d || !key.d->isValid)
return;
@@ -657,6 +688,8 @@ void QPixmapCache::remove(const Key &key)
void QPixmapCache::clear()
{
+ if (!QCoreApplication::closingDown() && !qt_pixmapcache_thread_test())
+ return;
QT_TRY {
if (pm_cache.exists())
pm_cache->clear();