QImage: introduce a class invariant that format() is in-range
Coverity complains that image.format() is used to index into qPixelLayouts[] when it may be NImageFormats. Most code paths (e.g. QImageData::create()) defended against that, but e.g. QImage::reinterpretAsFormat() did not (at least not overtly), as didn't some of the backend functions. Add checks, document the invariant on 'format' and assert it in QImage::format(). If this doesn't convince Coverity, we'll need to turn qPixelLayouts[] into a function, so that it can defend itself against out-of-bounds access. Pick-to: 6.9 6.8 Coverity-Id: 390711 Coverity-Id: 390720 Coverity-Id: 390758 Change-Id: I29431193face3cae8be56f01da8dced19c3abb38 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
1593220552
commit
a2e60ebee3
@ -2158,6 +2158,11 @@ void QImage::setColorCount(int colorCount)
|
|||||||
*/
|
*/
|
||||||
QImage::Format QImage::format() const
|
QImage::Format QImage::format() const
|
||||||
{
|
{
|
||||||
|
if (d) {
|
||||||
|
// Class Invariant Check
|
||||||
|
Q_ASSERT(d->format < NImageFormats);
|
||||||
|
Q_ASSERT(d->format > Format_Invalid);
|
||||||
|
}
|
||||||
return d ? d->format : Format_Invalid;
|
return d ? d->format : Format_Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2361,6 +2366,8 @@ QImage QImage::convertToFormat(Format format, const QList<QRgb> &colorTable, Qt:
|
|||||||
|
|
||||||
bool QImage::reinterpretAsFormat(Format format)
|
bool QImage::reinterpretAsFormat(Format format)
|
||||||
{
|
{
|
||||||
|
if (format <= Format_Invalid || format >= NImageFormats)
|
||||||
|
return false;
|
||||||
if (!d)
|
if (!d)
|
||||||
return false;
|
return false;
|
||||||
if (d->format == format)
|
if (d->format == format)
|
||||||
|
@ -345,6 +345,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
|
|||||||
{
|
{
|
||||||
// Cannot be used with indexed formats or between formats with different pixel depths.
|
// Cannot be used with indexed formats or between formats with different pixel depths.
|
||||||
Q_ASSERT(dst_format > QImage::Format_Indexed8);
|
Q_ASSERT(dst_format > QImage::Format_Indexed8);
|
||||||
|
Q_ASSERT(dst_format < QImage::NImageFormats);
|
||||||
Q_ASSERT(data->format > QImage::Format_Indexed8);
|
Q_ASSERT(data->format > QImage::Format_Indexed8);
|
||||||
const int destDepth = qt_depthForFormat(dst_format);
|
const int destDepth = qt_depthForFormat(dst_format);
|
||||||
if (data->depth < destDepth)
|
if (data->depth < destDepth)
|
||||||
@ -478,6 +479,7 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
|
|||||||
{
|
{
|
||||||
Q_ASSERT(data->format > QImage::Format_Indexed8);
|
Q_ASSERT(data->format > QImage::Format_Indexed8);
|
||||||
Q_ASSERT(dst_format > QImage::Format_Indexed8);
|
Q_ASSERT(dst_format > QImage::Format_Indexed8);
|
||||||
|
Q_ASSERT(dst_format < QImage::NImageFormats);
|
||||||
const int destDepth = qt_depthForFormat(dst_format);
|
const int destDepth = qt_depthForFormat(dst_format);
|
||||||
if (data->depth < destDepth)
|
if (data->depth < destDepth)
|
||||||
return false;
|
return false;
|
||||||
@ -572,6 +574,7 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
|
|||||||
{
|
{
|
||||||
Q_ASSERT(data->format >= QImage::Format_RGBX16FPx4);
|
Q_ASSERT(data->format >= QImage::Format_RGBX16FPx4);
|
||||||
Q_ASSERT(dst_format >= QImage::Format_RGBX16FPx4);
|
Q_ASSERT(dst_format >= QImage::Format_RGBX16FPx4);
|
||||||
|
Q_ASSERT(dst_format < QImage::NImageFormats);
|
||||||
const int destDepth = qt_depthForFormat(dst_format);
|
const int destDepth = qt_depthForFormat(dst_format);
|
||||||
if (data->depth < destDepth)
|
if (data->depth < destDepth)
|
||||||
return false;
|
return false;
|
||||||
@ -682,6 +685,8 @@ static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::Ima
|
|||||||
template<QImage::Format Format>
|
template<QImage::Format Format>
|
||||||
static bool convert_passthrough_inplace(QImageData *data, Qt::ImageConversionFlags)
|
static bool convert_passthrough_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||||
{
|
{
|
||||||
|
static_assert(Format > QImage::Format_Invalid);
|
||||||
|
static_assert(Format < QImage::NImageFormats);
|
||||||
data->format = Format;
|
data->format = Format;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -839,6 +844,8 @@ static void convert_ARGB_to_RGBA(QImageData *dest, const QImageData *src, Qt::Im
|
|||||||
template<QImage::Format DestFormat>
|
template<QImage::Format DestFormat>
|
||||||
static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags)
|
static bool convert_ARGB_to_RGBA_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||||
{
|
{
|
||||||
|
static_assert(DestFormat > QImage::Format_Invalid);
|
||||||
|
static_assert(DestFormat < QImage::NImageFormats);
|
||||||
Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied);
|
Q_ASSERT(data->format == QImage::Format_ARGB32 || data->format == QImage::Format_ARGB32_Premultiplied);
|
||||||
|
|
||||||
const int pad = (data->bytes_per_line >> 2) - data->width;
|
const int pad = (data->bytes_per_line >> 2) - data->width;
|
||||||
@ -885,6 +892,8 @@ static void convert_RGBA_to_ARGB(QImageData *dest, const QImageData *src, Qt::Im
|
|||||||
template<QImage::Format DestFormat>
|
template<QImage::Format DestFormat>
|
||||||
static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags)
|
static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||||
{
|
{
|
||||||
|
static_assert(DestFormat > QImage::Format_Invalid);
|
||||||
|
static_assert(DestFormat < QImage::NImageFormats);
|
||||||
Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied);
|
Q_ASSERT(data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888 || data->format == QImage::Format_RGBA8888_Premultiplied);
|
||||||
|
|
||||||
const int pad = (data->bytes_per_line >> 2) - data->width;
|
const int pad = (data->bytes_per_line >> 2) - data->width;
|
||||||
@ -1233,6 +1242,8 @@ static void mask_alpha_converter(QImageData *dest, const QImageData *src, Qt::Im
|
|||||||
template<QImage::Format DestFormat>
|
template<QImage::Format DestFormat>
|
||||||
static bool mask_alpha_converter_inplace(QImageData *data, Qt::ImageConversionFlags)
|
static bool mask_alpha_converter_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||||
{
|
{
|
||||||
|
static_assert(DestFormat > QImage::Format_Invalid);
|
||||||
|
static_assert(DestFormat < QImage::NImageFormats);
|
||||||
Q_ASSERT(data->format == QImage::Format_RGB32
|
Q_ASSERT(data->format == QImage::Format_RGB32
|
||||||
|| DestFormat == QImage::Format_RGB32
|
|| DestFormat == QImage::Format_RGB32
|
||||||
|| DestFormat == QImage::Format_RGBX8888);
|
|| DestFormat == QImage::Format_RGBX8888);
|
||||||
|
@ -49,7 +49,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data
|
|||||||
qreal devicePixelRatio;
|
qreal devicePixelRatio;
|
||||||
QList<QRgb> colortable;
|
QList<QRgb> colortable;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
QImage::Format format;
|
QImage::Format format; // invariants: > Format_Invalid, < NImageFormats
|
||||||
qsizetype bytes_per_line;
|
qsizetype bytes_per_line;
|
||||||
int ser_no; // serial number
|
int ser_no; // serial number
|
||||||
int detach_no;
|
int detach_no;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user