summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2020-06-05 13:35:03 +0200
committerEirik Aavitsland <eirik.aavitsland@qt.io>2020-06-26 15:23:58 +0200
commit5dea4fe956c452be5aae2c61dd0777fdf1efe5d0 (patch)
treee898d84182f7c3f55c93908b7fec63dfa1712607 /src
parentcc857a3c716729610ef61fa075f8d360684dae09 (diff)
Introduce a settable allocation limit on image loading
[ChangeLog][QtGui][QImageReader] Introduced a settable allocation limit on image loading to limit resource usage from corrupt image files. Change-Id: Ibed7b0cac32798125a060e6db80b17ebc5e70759 Task-number: QTBUG-85037 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/gui/image/qimageiohandler.cpp42
-rw-r--r--src/gui/image/qimageiohandler.h3
-rw-r--r--src/gui/image/qimagereader.cpp34
-rw-r--r--src/gui/image/qimagereader.h2
4 files changed, 80 insertions, 1 deletions
diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp
index 9c9ebbccdc..45c5891ccd 100644
--- a/src/gui/image/qimageiohandler.cpp
+++ b/src/gui/image/qimageiohandler.cpp
@@ -264,9 +264,10 @@
*/
#include "qimageiohandler.h"
+#include "qimage_p.h"
#include <qbytearray.h>
-#include <qimage.h>
+#include <qimagereader.h>
#include <qvariant.h>
QT_BEGIN_NAMESPACE
@@ -552,6 +553,45 @@ int QImageIOHandler::nextImageDelay() const
return 0;
}
+/*!
+ \since 6.0
+
+ This is a convenience method for the reading function in subclasses. Image
+ format handlers must reject loading an image if the required allocation
+ would exceeed the current allocation limit. This function checks the
+ parameters and limit, and does the allocation if it is valid and required.
+ Upon successful return, \a image will be a valid, detached QImage of the
+ given \a size and \a format.
+
+ \sa QImageReader::allocationLimit()
+*/
+bool QImageIOHandler::allocateImage(QSize size, QImage::Format format, QImage *image)
+{
+ Q_ASSERT(image);
+ if (size.isEmpty() || format <= QImage::Format_Invalid || format >= QImage::NImageFormats)
+ return false;
+
+ if (image->size() == size && image->format() == format) {
+ image->detach();
+ } else {
+ if (const int mbLimit = QImageReader::allocationLimit()) {
+ qsizetype depth = qt_depthForFormat(format);
+ QImageData::ImageSizeParameters szp =
+ QImageData::calculateImageParameters(size.width(), size.height(), depth);
+ if (!szp.isValid())
+ return false;
+ const qsizetype mb = szp.totalSize >> 20;
+ if (mb > mbLimit || (mb == mbLimit && szp.totalSize % (1 << 20))) {
+ qWarning("QImageIOHandler: Rejecting image as it exceeds the current "
+ "allocation limit of %i megabytes", mbLimit);
+ return false;
+ }
+ }
+ *image = QImage(size, format);
+ }
+ return !image->isNull();
+}
+
#ifndef QT_NO_IMAGEFORMATPLUGIN
/*!
diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h
index b6b40029b6..1923443997 100644
--- a/src/gui/image/qimageiohandler.h
+++ b/src/gui/image/qimageiohandler.h
@@ -41,6 +41,7 @@
#define QIMAGEIOHANDLER_H
#include <QtGui/qtguiglobal.h>
+#include <QtGui/qimage.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qplugin.h>
#include <QtCore/qfactoryinterface.h>
@@ -123,6 +124,8 @@ public:
virtual int currentImageNumber() const;
virtual QRect currentImageRect() const;
+ static bool allocateImage(QSize size, QImage::Format format, QImage *image);
+
protected:
QImageIOHandler(QImageIOHandlerPrivate &dd);
QScopedPointer<QImageIOHandlerPrivate> d_ptr;
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 684442eb8f..a3ff898222 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -492,8 +492,12 @@ public:
QString errorString;
QImageReader *q;
+
+ static int maxAlloc;
};
+int QImageReaderPrivate::maxAlloc = 128; // 128 MB is enough for an 8K 32bpp image
+
/*!
\internal
*/
@@ -1575,4 +1579,34 @@ QList<QByteArray> QImageReader::imageFormatsForMimeType(const QByteArray &mimeTy
QImageReaderWriterHelpers::CanRead);
}
+/*!
+ \since 6.0
+
+ Returns the current allocation limit, in megabytes.
+
+ \sa setAllocationLimit()
+*/
+int QImageReader::allocationLimit()
+{
+ return QImageReaderPrivate::maxAlloc;
+}
+
+/*!
+ \since 6.0
+
+ Sets the allocation limit to \a mbLimit megabytes. Images that would
+ require a QImage memory allocation above this limit will be rejected.
+
+ This limit helps applications avoid unexpectedly large memory usage from
+ loading corrupt image files. It is normally not needed to change it. The
+ default limit is large enough for all commonly used image sizes.
+
+ \sa allocationLimit()
+*/
+void QImageReader::setAllocationLimit(int mbLimit)
+{
+ if (mbLimit >= 0)
+ QImageReaderPrivate::maxAlloc = mbLimit;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h
index d40cbb89b8..4d418bd7d0 100644
--- a/src/gui/image/qimagereader.h
+++ b/src/gui/image/qimagereader.h
@@ -142,6 +142,8 @@ public:
static QList<QByteArray> supportedImageFormats();
static QList<QByteArray> supportedMimeTypes();
static QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType);
+ static int allocationLimit();
+ static void setAllocationLimit(int mbLimit);
private:
Q_DISABLE_COPY(QImageReader)