QByteDataBuffer: avoid silent failures of read(n)

On 32-bit platforms, the user can ask for more than INT_MAX bytes to
be returned from read(n), by way of its qint64 argument. We can, of
course, not return so much data because allocation would fail, so fail
early, by detecting this situation and do what resize() would have done
if it was not for the narrowing of its argument: throw bad_alloc.

Reviewers may ask themselves whether byteAmount(), which already caps
the request, would not have physically limited the request size to
INT_MAX, since we cannot possibly hold more data than that on 32-bit
platforms. But this is not correct, since QByteDataBuffer is
essentially a list of QByteArrays, and those can be shared copies of
each other (which isn't uncommon, if you consider how a user of the
class may be piecing together data by reusing existing QByteArrays).

The read(n) and readAll() functions are already documented to be
inefficient and should-not-use, we may want to remove them in the
future to force users to think about this problem in the context of
their domain.

Change-Id: Ia152db0a1fc65bbef35acd463f12fba1b7726d4a
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit db09fec6a1e08b05cd832a68e90857376c8e914e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2022-07-18 09:47:29 +02:00 committed by Qt Cherry-pick Bot
parent caa7970df8
commit a88f62b0c4

View File

@ -19,6 +19,8 @@
#include <qbytearray.h>
#include <QtCore/qlist.h>
#include <climits>
QT_BEGIN_NAMESPACE
// this class handles a list of QByteArrays. It is a variant of QRingBuffer
@ -120,8 +122,15 @@ public:
inline QByteArray read(qint64 amount)
{
amount = qMin(byteAmount(), amount);
if constexpr (sizeof(qsizetype) == sizeof(int)) { // 32-bit
// While we cannot overall have more than INT_MAX memory allocated,
// the QByteArrays we hold may be shared copies of each other,
// causing byteAmount() to exceed INT_MAX.
if (amount > INT_MAX)
qBadAlloc(); // what resize() would do if it saw past the truncation
}
QByteArray byteData;
byteData.resize(amount);
byteData.resize(qsizetype(amount));
read(byteData.data(), byteData.size());
return byteData;
}