diff options
author | Marc Mutz <marc.mutz@qt.io> | 2022-09-20 09:17:31 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2022-09-26 17:00:30 +0200 |
commit | fb9213e640b9b5612fd198b1d859d00a28642672 (patch) | |
tree | ee4375c97f1963c25f356de6179de99aab133d21 | |
parent | 98d9cfabc19984d75951f7ee66037331da63c0b8 (diff) |
qCompress: use saturation, not truncation, for the size header
This provides a better size hint than the pseudo-random mod 4GiB
number used before. In particular, it will make the Qt 5
implementation fail fast, because UINT_MAX will be recognized as a
non-representable size right away.
Pick-to: 6.4 6.3 6.2
Task-number: QTBUG-104972
Change-Id: I6010f558eb71bbf02fb0f71bee1b3b1a15ec6e3f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r-- | src/corelib/global/qnumeric_p.h | 30 | ||||
-rw-r--r-- | src/corelib/text/qbytearray.cpp | 2 |
2 files changed, 31 insertions, 1 deletions
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 7c65b67b7a..8e08615ab3 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -314,6 +314,36 @@ template <auto V2, typename T> bool mul_overflow(T v1, T *r) } #endif // Q_CLANG_QDOC +/* + Safely narrows \a x to \c{To}. Let \c L be + \c{std::numeric_limit<To>::min()} and \c H be \c{std::numeric_limit<To>::max()}. + + If \a x is less than L, returns L. If \a x is greater than H, + returns H. Otherwise, returns \c{To(x)}. +*/ +template <typename To, typename From> +static auto qt_saturate(From x) +{ + static_assert(std::is_integral_v<To>); + static_assert(std::is_integral_v<From>); + + [[maybe_unused]] + constexpr auto Lo = (std::numeric_limits<To>::min)(); + constexpr auto Hi = (std::numeric_limits<To>::max)(); + + if constexpr (std::is_signed_v<From> == std::is_signed_v<To>) { + return x < Lo ? Lo : + x > Hi ? Hi : + /*else*/ To(x); + } else { + if constexpr (std::is_signed_v<From>) { // ie. !is_signed_v<To> + if (x < From{0}) + return To{0}; + } + return x > Hi ? Hi : To(x); + } +} + QT_END_NAMESPACE #endif // QNUMERIC_P_H diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index fb55c630bf..33292d9ca2 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -603,7 +603,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel) switch (res) { case Z_OK: bazip.resize(len + HeaderSize); - qToBigEndian(CompressSizeHint_t(nbytes), bazip.data()); + qToBigEndian(qt_saturate<CompressSizeHint_t>(nbytes), bazip.data()); break; case Z_MEM_ERROR: return tooMuchData(ZLibOp::Compression); |