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>
This commit is contained in:
Eirik Aavitsland 2020-06-05 13:35:03 +02:00
parent cc857a3c71
commit 5dea4fe956
4 changed files with 80 additions and 1 deletions

View File

@ -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
/*!

View File

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

View File

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

View File

@ -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)