diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2018-11-01 21:43:48 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2018-11-08 15:20:01 +0000 |
commit | 9d90c0edac91b35ec96646fd3e6cdd339639ca79 (patch) | |
tree | ef5d3b2df364e610e0248053046a567c3978ee3d /src/gui/image/qimage.cpp | |
parent | f80ed83cd92deb015b78c39f4c634c046ef75b1c (diff) |
QImage: merge the size calculations with proper (non-UB) checks
This check, which was only done once, was wrong:
const int bytes_per_line = ((width * depth + 31) >> 5) << 2;
// sanity check for potential overflows
if (std::numeric_limits<int>::max()/depth < width
If width*height overflows, then it's already UB and checking afterwards
with a division is pointless and slow.
The other instances weren't properly guarding against overflows.
Change-Id: I343f2beed55440a7ac0bfffd1563350d4cfa639c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src/gui/image/qimage.cpp')
-rw-r--r-- | src/gui/image/qimage.cpp | 72 |
1 files changed, 31 insertions, 41 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 421362dd9e..0105f1decd 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -118,21 +118,14 @@ QImageData::QImageData() QImageData * QImageData::create(const QSize &size, QImage::Format format) { if (!size.isValid() || format == QImage::Format_Invalid) - return 0; // invalid parameter(s) + return nullptr; // invalid parameter(s) - uint width = size.width(); - uint height = size.height(); - uint depth = qt_depthForFormat(format); - - const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4) - - // sanity check for potential overflows - if (std::numeric_limits<int>::max()/depth < width - || bytes_per_line <= 0 - || height <= 0 - || std::numeric_limits<qsizetype>::max()/uint(bytes_per_line) < height - || std::numeric_limits<int>::max()/sizeof(uchar *) < uint(height)) - return 0; + int width = size.width(); + int height = size.height(); + int depth = qt_depthForFormat(format); + auto params = calculateImageParameters(width, height, depth); + if (params.bytesPerLine < 0) + return nullptr; QScopedPointer<QImageData> d(new QImageData); @@ -154,18 +147,15 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format) d->has_alpha_clut = false; d->is_cached = false; - d->bytes_per_line = bytes_per_line; - - d->nbytes = d->bytes_per_line*height; + d->bytes_per_line = params.bytesPerLine; + d->nbytes = params.totalSize; d->data = (uchar *)malloc(d->nbytes); - if (!d->data) { - return 0; - } + if (!d->data) + return nullptr; d->ref.ref(); return d.take(); - } QImageData::~QImageData() @@ -786,27 +776,27 @@ QImage::QImage(const QSize &size, Format format) QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo) { - QImageData *d = 0; - - if (format == QImage::Format_Invalid) - return d; + if (width <= 0 || height <= 0 || !data || format == QImage::Format_Invalid) + return nullptr; const int depth = qt_depthForFormat(format); - const int calc_bytes_per_line = ((width * depth + 31)/32) * 4; - const int min_bytes_per_line = (width * depth + 7)/8; - - if (bpl <= 0) - bpl = calc_bytes_per_line; - - if (width <= 0 || height <= 0 || !data - || INT_MAX/sizeof(uchar *) < uint(height) - || INT_MAX/uint(depth) < uint(width) - || bpl <= 0 - || bpl < min_bytes_per_line - || INT_MAX/uint(bpl) < uint(height)) - return d; // invalid parameter(s) + auto params = calculateImageParameters(width, height, depth); + if (params.totalSize < 0) + return nullptr; + + if (bpl > 0) { + // can't overflow, because has calculateImageParameters already done this multiplication + const int min_bytes_per_line = (width * depth + 7)/8; + if (bpl < min_bytes_per_line) + return nullptr; + + // recalculate the total with this value + params.bytesPerLine = bpl; + if (mul_overflow<qsizetype>(bpl, height, ¶ms.totalSize)) + return nullptr; + } - d = new QImageData; + QImageData *d = new QImageData; d->ref.ref(); d->own_data = false; @@ -817,8 +807,8 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm d->depth = depth; d->format = format; - d->bytes_per_line = bpl; - d->nbytes = d->bytes_per_line * height; + d->bytes_per_line = params.bytesPerLine; + d->nbytes = params.totalSize; d->cleanupFunction = cleanupFunction; d->cleanupInfo = cleanupInfo; |