qUncompress(): introduce more functions a la invalidCompressedData()
... and use them consistently instead of naked qWarning()s. As a drive-by, fix the warnings we generate on failures, which all-too-often was "invalid data". Code for minimal size by DRYing what the compiler can't, and using Q_DECL_COLD_FUNCTION to avoid excessive inlining. Left the one qWarning() in qCompress(), for now, because that would have changed the return value from an empty to a null byte array. Move invalidCompressedData() to where the others are defined, too, because it's required by a follow-up commit. Pick-to: 6.4 6.3 6.2 Task-number: QTBUG-104972 Change-Id: Ia43aa315960b06530e98c1d7525ccf0e7f71bb5c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
ce4c26c8d1
commit
6472616e6c
@ -532,16 +532,53 @@ quint16 qChecksum(QByteArrayView data, Qt::ChecksumType standard)
|
|||||||
#ifndef QT_NO_COMPRESS
|
#ifndef QT_NO_COMPRESS
|
||||||
using CompressSizeHint_t = quint32; // 32-bit BE, historically
|
using CompressSizeHint_t = quint32; // 32-bit BE, historically
|
||||||
|
|
||||||
|
enum class ZLibOp : bool { Compression, Decompression };
|
||||||
|
|
||||||
|
Q_DECL_COLD_FUNCTION
|
||||||
|
static const char *zlibOpAsString(ZLibOp op)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case ZLibOp::Compression: return "qCompress";
|
||||||
|
case ZLibOp::Decompression: return "qUncompress";
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECL_COLD_FUNCTION
|
||||||
|
static QByteArray zlibError(ZLibOp op, const char *what)
|
||||||
|
{
|
||||||
|
qWarning("%s: %s", zlibOpAsString(op), what);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECL_COLD_FUNCTION
|
||||||
|
static QByteArray dataIsNull(ZLibOp op)
|
||||||
|
{
|
||||||
|
return zlibError(op, "Data is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECL_COLD_FUNCTION
|
||||||
|
static QByteArray tooMuchData(ZLibOp op)
|
||||||
|
{
|
||||||
|
return zlibError(op, "Not enough memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_DECL_COLD_FUNCTION
|
||||||
|
static QByteArray invalidCompressedData()
|
||||||
|
{
|
||||||
|
return zlibError(ZLibOp::Decompression, "Input data is corrupted");
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
|
QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
|
||||||
{
|
{
|
||||||
constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
|
constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
return QByteArray(HeaderSize, '\0');
|
return QByteArray(HeaderSize, '\0');
|
||||||
}
|
}
|
||||||
if (!data) {
|
if (!data)
|
||||||
qWarning("qCompress: Data is null");
|
return dataIsNull(ZLibOp::Compression);
|
||||||
return QByteArray();
|
|
||||||
}
|
|
||||||
if (compressionLevel < -1 || compressionLevel > 9)
|
if (compressionLevel < -1 || compressionLevel > 9)
|
||||||
compressionLevel = -1;
|
compressionLevel = -1;
|
||||||
|
|
||||||
@ -606,13 +643,6 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef QT_NO_COMPRESS
|
#ifndef QT_NO_COMPRESS
|
||||||
Q_DECL_COLD_FUNCTION
|
|
||||||
static QByteArray invalidCompressedData()
|
|
||||||
{
|
|
||||||
qWarning("qUncompress: Input data is corrupted");
|
|
||||||
return QByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \relates QByteArray
|
/*! \relates QByteArray
|
||||||
|
|
||||||
\overload
|
\overload
|
||||||
@ -624,10 +654,8 @@ static QByteArray invalidCompressedData()
|
|||||||
*/
|
*/
|
||||||
QByteArray qUncompress(const uchar* data, qsizetype nbytes)
|
QByteArray qUncompress(const uchar* data, qsizetype nbytes)
|
||||||
{
|
{
|
||||||
if (!data) {
|
if (!data)
|
||||||
qWarning("qUncompress: Data is null");
|
return dataIsNull(ZLibOp::Decompression);
|
||||||
return QByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
|
constexpr qsizetype HeaderSize = sizeof(CompressSizeHint_t);
|
||||||
if (nbytes < HeaderSize)
|
if (nbytes < HeaderSize)
|
||||||
@ -643,12 +671,12 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
|
|||||||
constexpr size_t MaxZLibSize = (std::numeric_limits<uLong>::max)();
|
constexpr size_t MaxZLibSize = (std::numeric_limits<uLong>::max)();
|
||||||
constexpr size_t MaxDecompressedSize = (std::min)(size_t(MaxByteArraySize), MaxZLibSize);
|
constexpr size_t MaxDecompressedSize = (std::min)(size_t(MaxByteArraySize), MaxZLibSize);
|
||||||
if (len > MaxDecompressedSize)
|
if (len > MaxDecompressedSize)
|
||||||
return invalidCompressedData();
|
return tooMuchData(ZLibOp::Decompression);
|
||||||
|
|
||||||
Q_ASSERT(len <= size_t((std::numeric_limits<qsizetype>::max)()));
|
Q_ASSERT(len <= size_t((std::numeric_limits<qsizetype>::max)()));
|
||||||
QByteArray::DataPointer d(QByteArray::Data::allocate(qsizetype(len)));
|
QByteArray::DataPointer d(QByteArray::Data::allocate(qsizetype(len)));
|
||||||
if (d.data() == nullptr) // allocation failed
|
if (d.data() == nullptr) // allocation failed
|
||||||
return invalidCompressedData();
|
return tooMuchData(ZLibOp::Decompression);
|
||||||
|
|
||||||
forever {
|
forever {
|
||||||
const auto alloc = len;
|
const auto alloc = len;
|
||||||
@ -665,23 +693,21 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Z_MEM_ERROR:
|
case Z_MEM_ERROR:
|
||||||
qWarning("qUncompress: Z_MEM_ERROR: Not enough memory");
|
return tooMuchData(ZLibOp::Decompression);
|
||||||
return QByteArray();
|
|
||||||
|
|
||||||
case Z_BUF_ERROR:
|
case Z_BUF_ERROR:
|
||||||
if (len == MaxDecompressedSize) // can't grow further
|
if (len == MaxDecompressedSize) // can't grow further
|
||||||
return invalidCompressedData();
|
return tooMuchData(ZLibOp::Decompression);
|
||||||
if (qMulOverflow<2>(len, &len))
|
if (qMulOverflow<2>(len, &len))
|
||||||
len = MaxDecompressedSize;
|
len = MaxDecompressedSize;
|
||||||
d->reallocate(qsizetype(len), QArrayData::Grow); // cannot overflow!
|
d->reallocate(qsizetype(len), QArrayData::Grow); // cannot overflow!
|
||||||
if (d.data() == nullptr) // reallocation failed
|
if (d.data() == nullptr) // reallocation failed
|
||||||
return invalidCompressedData();
|
return tooMuchData(ZLibOp::Decompression);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case Z_DATA_ERROR:
|
case Z_DATA_ERROR:
|
||||||
qWarning("qUncompress: Z_DATA_ERROR: Input data is corrupted");
|
return invalidCompressedData();
|
||||||
return QByteArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user