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 -#include +#include #include 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 +#include #include #include #include @@ -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 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 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 supportedImageFormats(); static QList supportedMimeTypes(); static QList imageFormatsForMimeType(const QByteArray &mimeType); + static int allocationLimit(); + static void setAllocationLimit(int mbLimit); private: Q_DISABLE_COPY(QImageReader)