Fix QDataStream::operator<<(const char *) to handle 64-bit length

The operator was not converted to using a new streaming version, so it
supported only 32-bit length.

Fix it and add a manual test for serialization/deserialization of
large c-style strings.

Amends fd48ce0b73c74dafd5db27bc1f2752ef665df7ef

Change-Id: I83704edec021d400b992de810feba5da52d5ffe1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit 0aaf7092cd077eb07e62d3742293f146c65c9630)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2024-01-29 11:57:37 +01:00 committed by Qt Cherry-pick Bot
parent cc1476c608
commit 635be3cdf1
2 changed files with 53 additions and 7 deletions

View File

@ -1344,13 +1344,9 @@ QDataStream &QDataStream::operator<<(double f)
QDataStream &QDataStream::operator<<(const char *s)
{
if (!s) {
*this << (quint32)0;
return *this;
}
int len = int(qstrlen(s)) + 1; // also write null terminator
*this << (quint32)len; // write length specifier
writeRawData(s, len);
// Include null terminator, unless s itself is null
const qint64 len = s ? qint64(qstrlen(s)) + 1 : 0;
writeBytes(s, len);
return *this;
}

View File

@ -5,6 +5,7 @@
#include <QHash>
#include <QList>
#include <QMap>
#include <QScopeGuard>
#include <QSet>
#include <QTest>
@ -32,6 +33,7 @@ private slots:
void stream_bigQSet();
void stream_bigQMap();
void stream_bigQHash();
void stream_bigCString();
};
void tst_QDataStream::initTestCase()
@ -161,6 +163,54 @@ void tst_QDataStream::stream_bigQHash()
stream_big<QHash<qsizetype, qsizetype>>();
}
void tst_QDataStream::stream_bigCString()
{
if constexpr (sizeof(void*) == sizeof(int))
QSKIP("This test is 64-bit only.");
QFETCH_GLOBAL(const QDataStream::Version, streamVersion);
constexpr qint64 GiB = 1024 * 1024 * 1024;
constexpr qint64 BaseSize = 4 * GiB + 1;
std::string input;
qDebug("Creating an array with %lld entries", BaseSize);
QElapsedTimer timer;
timer.start();
try {
input.resize(BaseSize, 'a');
} catch (const std::bad_alloc &) {
QSKIP("Could not allocate 4 Gi + 2 entries.");
}
qDebug("Created dataset in %lld ms", timer.elapsed());
QByteArray ba;
QDataStream inputstream(&ba, QIODevice::WriteOnly);
inputstream.setVersion(streamVersion);
timer.start();
try {
inputstream << input.data();
} catch (const std::bad_alloc &) {
QSKIP("Not enough memory to copy into QDataStream.");
}
qDebug("Streamed into QDataStream in %lld ms", timer.elapsed());
if (streamVersion < QDataStream::Qt_6_7) {
// old versions do not support data size more than 4 GiB
QCOMPARE(inputstream.status(), QDataStream::SizeLimitExceeded);
QVERIFY(ba.isEmpty());
} else {
char *output = nullptr;
auto cleanup = qScopeGuard([&output] { delete [] output; });
QDataStream outputstream(ba);
timer.start();
try {
outputstream >> output;
} catch (const std::bad_alloc &) {
QSKIP("Not enough memory to copy out of QDataStream.");
}
qDebug("Streamed out of QDataStream in %lld ms", timer.elapsed());
QCOMPARE(qstrlen(output), input.size());
QVERIFY(memcmp(input.data(), output, BaseSize + 1) == 0);
}
}
QTEST_MAIN(tst_QDataStream)
#include "tst_manualqdatastream.moc"