diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp index d67908bb2cd..442f5f1e53d 100644 --- a/src/corelib/serialization/qdatastream.cpp +++ b/src/corelib/serialization/qdatastream.cpp @@ -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; } diff --git a/tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp b/tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp index 3f63fe5e425..334f27dc936 100644 --- a/tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp +++ b/tests/manual/corelib/qdatastream/tst_manualqdatastream.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -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>(); } +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"