QDataStream::readBytes: do not leak the memory in case of bad_alloc

The algorithm was leaking the previous buffer if the attempt to
allocate a new one failed with std::bad_alloc.

Wrap the buffer allocations into std::unique_ptr, so that we do
not leak the buffer in case of bad_alloc.

This patch is not changing the behavior of QDataStream, so it's
NOT handling the bad_alloc exception, and also does not change
the state of the buffer in case the exception occurs.

Pick-to: 6.5
Change-Id: I5558a6d03768094e4ee83ca47cacf4e09c36f1cf
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit e176dd78fd2f253eb2625585b2bd90b5713e5984)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2024-04-26 17:25:25 +02:00 committed by Qt Cherry-pick Bot
parent 232a866ea8
commit 06bb5f19bf

View File

@ -1113,28 +1113,22 @@ QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
qsizetype step = 1024 * 1024;
qsizetype allocated = 0;
char *prevBuf = nullptr;
char *curBuf = nullptr;
std::unique_ptr<char[]> curBuf = nullptr;
constexpr qsizetype StepIncreaseThreshold = std::numeric_limits<qsizetype>::max() / 2;
do {
qsizetype blockSize = qMin(step, len - allocated);
prevBuf = curBuf;
curBuf = new char[allocated + blockSize + 1];
if (prevBuf) {
memcpy(curBuf, prevBuf, allocated);
delete [] prevBuf;
}
if (readBlock(curBuf + allocated, blockSize) != blockSize) {
delete [] curBuf;
const qsizetype n = allocated + blockSize + 1;
if (const auto prevBuf = std::exchange(curBuf, std::make_unique<char[]>(n)))
memcpy(curBuf.get(), prevBuf.get(), allocated);
if (readBlock(curBuf.get() + allocated, blockSize) != blockSize)
return *this;
}
allocated += blockSize;
if (step <= StepIncreaseThreshold)
step *= 2;
} while (allocated < len);
s = curBuf;
s = curBuf.release();
s[len] = '\0';
l = len;
return *this;