From 14f1ec186f87ce50037044ccb079463676518ec5 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 13 Feb 2019 11:31:14 +0100 Subject: Make bytes-per-line safe for int overflow Goes through the Qt code and make sure bytes-per-line calculations are safe when they are too big for 32bit integers. Change-Id: I88b2d74b3da82e91407d316aa932a4a37587c0cf Reviewed-by: Lars Knoll --- src/gui/image/qbmphandler.cpp | 8 ++++++-- src/gui/image/qimage.cpp | 30 +++++++++++++++++++----------- src/gui/image/qimage.h | 5 +++++ src/gui/image/qimage_p.h | 2 +- src/gui/image/qpixmap_win.cpp | 2 +- src/gui/image/qplatformpixmap.cpp | 4 ++-- src/gui/image/qplatformpixmap.h | 2 +- src/gui/image/qpnghandler.cpp | 4 ++-- src/gui/image/qppmhandler.cpp | 18 +++++++++--------- 9 files changed, 46 insertions(+), 29 deletions(-) (limited to 'src/gui/image') diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 32b6131309..d447faaceb 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -777,9 +777,9 @@ bool QBmpHandler::write(const QImage &img) } int nbits; - int bpl_bmp; + qsizetype bpl_bmp; // Calculate a minimum bytes-per-line instead of using whatever value this QImage is using internally. - int bpl = ((image.width() * image.depth() + 31) >> 5) << 2; + qsizetype bpl = ((image.width() * image.depth() + 31) >> 5) << 2; if (image.depth() == 8 && image.colorCount() <= 16) { bpl_bmp = (((bpl+1)/2+3)/4)*4; @@ -791,6 +791,8 @@ bool QBmpHandler::write(const QImage &img) bpl_bmp = bpl; nbits = image.depth(); } + if (qsizetype(int(bpl_bmp)) != bpl_bmp) + return false; if (m_format == DibFormat) { QDataStream dibStream(device()); @@ -813,6 +815,8 @@ bool QBmpHandler::write(const QImage &img) bf.bfReserved2 = 0; bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4; bf.bfSize = bf.bfOffBits + bpl_bmp*image.height(); + if (qsizetype(bf.bfSize) != bf.bfOffBits + bpl_bmp*image.height()) + return false; s << bf; // write image diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 1319d9dffc..684051786d 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -781,7 +781,7 @@ 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 *QImageData::create(uchar *data, int width, int height, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo) { if (width <= 0 || height <= 0 || !data || format == QImage::Format_Invalid) return nullptr; @@ -793,7 +793,7 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm if (bpl > 0) { // can't overflow, because has calculateImageParameters already done this multiplication - const int min_bytes_per_line = (width * depth + 7)/8; + const qsizetype min_bytes_per_line = (qsizetype(width) * depth + 7)/8; if (bpl < min_bytes_per_line) return nullptr; @@ -894,13 +894,17 @@ QImage::QImage(const uchar* data, int width, int height, Format format, QImageCl initially empty and must be sufficiently expanded with setColorCount() or setColorTable() before the image is used. */ + +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +QImage::QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo) +#else QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo) +#endif :QPaintDevice() { d = QImageData::create(data, width, height, bytesPerLine, format, false, cleanupFunction, cleanupInfo); } - /*! Constructs an image with the given \a width, \a height and \a format, that uses an existing memory buffer, \a data. The \a width @@ -926,7 +930,11 @@ QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format form data being changed. */ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +QImage::QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo) +#else QImage::QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo) +#endif :QPaintDevice() { d = QImageData::create(const_cast(data), width, height, bytesPerLine, format, true, cleanupFunction, cleanupInfo); @@ -1165,7 +1173,7 @@ QImage QImage::copy(const QRect& r) const // Qt for Embedded Linux can create images with non-default bpl // make sure we don't crash. if (image.d->nbytes != d->nbytes) { - int bpl = qMin(bytesPerLine(), image.bytesPerLine()); + qsizetype bpl = qMin(bytesPerLine(), image.bytesPerLine()); for (int i = 0; i < height(); i++) memcpy(image.scanLine(i), scanLine(i), bpl); } else @@ -1224,7 +1232,7 @@ QImage QImage::copy(const QRect& r) const if (byteAligned) { const uchar *src = d->data + ((x * d->depth) >> 3) + y * d->bytes_per_line; uchar *dest = image.d->data + ((dx * d->depth) >> 3) + dy * image.d->bytes_per_line; - const int bytes_to_copy = (pixels_to_copy * d->depth) >> 3; + const qsizetype bytes_to_copy = (qsizetype(pixels_to_copy) * d->depth) >> 3; for (int i = 0; i < lines_to_copy; ++i) { memcpy(dest, src, bytes_to_copy); src += d->bytes_per_line; @@ -1890,11 +1898,11 @@ void QImage::invertPixels(InvertMode mode) if (depth() < 32) { // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit. - int bpl = (d->width * d->depth + 7) / 8; + qsizetype bpl = (qsizetype(d->width) * d->depth + 7) / 8; int pad = d->bytes_per_line - bpl; uchar *sl = d->data; for (int y=0; yheight; ++y) { - for (int x=0; xformat; @@ -4767,7 +4775,7 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode // create target image (some of the code is from QImage::copy()) int type = format() == Format_Mono ? QT_XFORM_TYPE_MSBFIRST : QT_XFORM_TYPE_LSBFIRST; - int dbpl = dImage.bytesPerLine(); + qsizetype dbpl = dImage.bytesPerLine(); qt_xForm_helper(mat, 0, type, bpp, dImage.bits(), dbpl, 0, hd, sptr, sbpl, ws, hs); } copyMetadata(dImage.d, d); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 35dc41be2d..a9c0fbbe3e 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -117,8 +117,13 @@ public: QImage(int width, int height, Format format); QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); QImage(const uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QImage(uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); + QImage(const uchar *data, int width, int height, qsizetype bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); +#else QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); +#endif #ifndef QT_NO_IMAGEFORMAT_XPM explicit QImage(const char * const xpm[]); diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 9277472c3c..6f6f626858 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -67,7 +67,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data QImageData(); ~QImageData(); static QImageData *create(const QSize &size, QImage::Format format); - static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); + static QImageData *create(uchar *data, int w, int h, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr); QAtomicInt ref; diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 8aad77b991..be6cd0c5fc 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -121,7 +121,7 @@ static inline void copyImageDataCreateAlpha(const uchar *data, QImage *target) const uint mask = target->format() == QImage::Format_RGB32 ? 0xff000000 : 0; const int height = target->height(); const int width = target->width(); - const int bytesPerLine = width * int(sizeof(QRgb)); + const qsizetype bytesPerLine = width * sizeof(QRgb); for (int y = 0; y < height; ++y) { QRgb *dest = reinterpret_cast(target->scanLine(y)); const QRgb *src = reinterpret_cast(data + y * bytesPerLine); diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index 493f55514e..ea4243ba07 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -183,7 +183,7 @@ QBitmap QPlatformPixmap::mask() const mask.setColor(0, QColor(Qt::color0).rgba()); mask.setColor(1, QColor(Qt::color1).rgba()); - const int bpl = mask.bytesPerLine(); + const qsizetype bpl = mask.bytesPerLine(); for (int y = 0; y < h; ++y) { const QRgb *src = reinterpret_cast(image.scanLine(y)); @@ -216,7 +216,7 @@ void QPlatformPixmap::setMask(const QBitmap &mask) for (int y = 0; y < h; ++y) { const uchar *mscan = imageMask.scanLine(y); uchar *tscan = image.scanLine(y); - int bytesPerLine = image.bytesPerLine(); + qsizetype bytesPerLine = image.bytesPerLine(); for (int i = 0; i < bytesPerLine; ++i) tscan[i] &= mscan[i]; } diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index 7635ac2949..9c7f5e5edf 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -163,7 +163,7 @@ private: # define QT_XFORM_TYPE_MSBFIRST 0 # define QT_XFORM_TYPE_LSBFIRST 1 -Q_GUI_EXPORT bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, int, int, int, const uchar*, int, int, int); +Q_GUI_EXPORT bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, qsizetype, int, int, const uchar*, qsizetype, int, int); QT_END_NAMESPACE diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 8435e5a0fe..e6a3604ad4 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -455,7 +455,7 @@ static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop i png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr); png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type); uchar *data = outImage->bits(); - int bpl = outImage->bytesPerLine(); + qsizetype bpl = outImage->bytesPerLine(); if (scaledSize.isEmpty() || !width || !height) return; @@ -709,7 +709,7 @@ bool QPngHandlerPrivate::readPngImage(QImage *outImage) png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr); png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type); uchar *data = outImage->bits(); - int bpl = outImage->bytesPerLine(); + qsizetype bpl = outImage->bytesPerLine(); amp.row_pointers = new png_bytep[height]; for (uint y = 0; y < height; y++) diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 13ee2eadd2..195e58d283 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -135,7 +135,7 @@ static inline QRgb scale_pbm_color(quint16 mx, quint16 rv, quint16 gv, quint16 b static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, QImage *outImage) { int nbits, y; - int pbm_bpl; + qsizetype pbm_bpl; bool raw; QImage::Format format; @@ -166,7 +166,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q return false; } - pbm_bpl = (nbits*w+7)/8; // bytes per scanline in PBM + pbm_bpl = (qsizetype(w) * nbits + 7) / 8; // bytes per scanline in PBM if (raw) { // read raw data if (nbits == 32) { // type 6 @@ -225,14 +225,14 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q if (device->read((char *)p, pbm_bpl) != pbm_bpl) return false; if (nbits == 8 && mcc < 255) { - for (int i = 0; i < pbm_bpl; i++) + for (qsizetype i = 0; i < pbm_bpl; i++) p[i] = (p[i] * 255) / mcc; } } } } else { // read ascii data uchar *p; - int n; + qsizetype n; char buf; for (y = 0; (y < h) && (device->peek(&buf, 1) == 1); y++) { p = outImage->scanLine(y); @@ -367,7 +367,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - uint bpl = w * (gray ? 1 : 3); + qsizetype bpl = qsizetype(w) * (gray ? 1 : 3); uchar *buf = new uchar[bpl]; if (image.format() == QImage::Format_Indexed8) { QVector color = image.colorTable(); @@ -388,7 +388,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy *p++ = qBlue(rgb); } } - if (bpl != (uint)out->write((char*)buf, bpl)) + if (bpl != (qsizetype)out->write((char*)buf, bpl)) return false; } } else { @@ -407,7 +407,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy *p++ = color; } } - if (bpl != (uint)out->write((char*)buf, bpl)) + if (bpl != (qsizetype)out->write((char*)buf, bpl)) return false; } } @@ -420,7 +420,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy str.append("255\n"); if (out->write(str, str.length()) != str.length()) return false; - uint bpl = w * 3; + qsizetype bpl = qsizetype(w) * 3; uchar *buf = new uchar[bpl]; for (uint y=0; y(image.constScanLine(y)); @@ -432,7 +432,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy *p++ = qGreen(rgb); *p++ = qBlue(rgb); } - if (bpl != (uint)out->write((char*)buf, bpl)) + if (bpl != (qsizetype)out->write((char*)buf, bpl)) return false; } delete [] buf; -- cgit v1.2.3