summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qdatastream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/serialization/qdatastream.cpp')
-rw-r--r--src/corelib/serialization/qdatastream.cpp271
1 files changed, 123 insertions, 148 deletions
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index ec3bd06a34..57713d3645 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdatastream.h"
#include "qdatastream_p.h"
@@ -51,9 +15,13 @@
QT_BEGIN_NAMESPACE
+constexpr quint32 QDataStream::NullCode;
+constexpr quint32 QDataStream::ExtendedSize;
+
/*!
\class QDataStream
\inmodule QtCore
+ \ingroup qtserialization
\reentrant
\brief The QDataStream class provides serialization of binary data
to a QIODevice.
@@ -199,6 +167,27 @@ QT_BEGIN_NAMESPACE
If no full packet is received, this code restores the stream to the
initial position, after which you need to wait for more data to arrive.
+ \section1 Corruption and Security
+
+ QDataStream is not resilient against corrupted data inputs and should
+ therefore not be used for security-sensitive situations, even when using
+ transactions. Transactions will help determine if a valid input can
+ currently be decoded with the data currently available on an asynchronous
+ device, but will assume that the data that is available is correctly
+ formed.
+
+ Additionally, many QDataStream demarshalling operators will allocate memory
+ based on information found in the stream. Those operators perform no
+ verification on whether the requested amount of memory is reasonable or if
+ it is compatible with the amount of data available in the stream (example:
+ demarshalling a QByteArray or QString may see the request for allocation of
+ several gigabytes of data).
+
+ QDataStream should not be used on content whose provenance cannot be
+ trusted. Applications should be designed to attempt to decode only streams
+ whose provenance is at least as trustworthy as that of the application
+ itself or its plugins.
+
\sa QTextStream, QVariant
*/
@@ -236,6 +225,11 @@ QT_BEGIN_NAMESPACE
data in the underlying device.
\value ReadCorruptData The data stream has read corrupt data.
\value WriteFailed The data stream cannot write to the underlying device.
+ \value [since 6.7] SizeLimitExceeded The data stream cannot read or write
+ the data because its size is larger than supported
+ by the current platform. This can happen, for
+ example, when trying to read more that 2 GiB of
+ data on a 32-bit platform.
*/
/*****************************************************************************
@@ -264,7 +258,7 @@ QT_BEGIN_NAMESPACE
return retVal;
#define CHECK_STREAM_TRANSACTION_PRECOND(retVal) \
- if (!d || d->transactionDepth == 0) { \
+ if (transactionDepth == 0) { \
qWarning("QDataStream: No transaction in progress"); \
return retVal; \
}
@@ -277,12 +271,6 @@ QT_BEGIN_NAMESPACE
QDataStream::QDataStream()
{
- dev = nullptr;
- owndev = false;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -294,11 +282,6 @@ QDataStream::QDataStream()
QDataStream::QDataStream(QIODevice *d)
{
dev = d; // set device
- owndev = false;
- byteorder = BigEndian; // default byte order
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -323,10 +306,6 @@ QDataStream::QDataStream(QByteArray *a, OpenMode flags)
buf->open(flags);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -347,10 +326,6 @@ QDataStream::QDataStream(const QByteArray &a)
buf->open(QIODevice::ReadOnly);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -412,16 +387,14 @@ bool QDataStream::atEnd() const
}
/*!
+ \fn QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+
Returns the floating point precision of the data stream.
\since 4.6
\sa FloatingPointPrecision, setFloatingPointPrecision()
*/
-QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
-{
- return d ? d->floatingPointPrecision : QDataStream::DoublePrecision;
-}
/*!
Sets the floating point precision of the data stream to \a precision. If the floating point precision is
@@ -445,22 +418,17 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
*/
void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision)
{
- if (!d)
- d.reset(new QDataStreamPrivate());
- d->floatingPointPrecision = precision;
+ fpPrecision = precision;
}
/*!
+ \fn QDataStream::status() const
+
Returns the status of the data stream.
\sa Status, setStatus(), resetStatus()
*/
-QDataStream::Status QDataStream::status() const
-{
- return q_status;
-}
-
/*!
Resets the status of the data stream.
@@ -508,11 +476,14 @@ void QDataStream::setStatus(Status status)
void QDataStream::setByteOrder(ByteOrder bo)
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ // accessed by inline byteOrder() prior to Qt 6.8
byteorder = bo;
+#endif
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- noswap = (byteorder == BigEndian);
+ noswap = (bo == BigEndian);
else
- noswap = (byteorder == LittleEndian);
+ noswap = (bo == LittleEndian);
}
@@ -558,6 +529,11 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_1 Same as Qt_6_0
\value Qt_6_2 Same as Qt_6_0
\value Qt_6_3 Same as Qt_6_0
+ \value Qt_6_4 Same as Qt_6_0
+ \value Qt_6_5 Same as Qt_6_0
+ \value Qt_6_6 Version 21 (Qt 6.6)
+ \value Qt_6_7 Version 22 (Qt 6.7)
+ \value Qt_6_8 Same as Qt_6_7
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -631,10 +607,7 @@ void QDataStream::startTransaction()
{
CHECK_STREAM_PRECOND(Q_VOID)
- if (!d)
- d.reset(new QDataStreamPrivate());
-
- if (++d->transactionDepth == 1) {
+ if (++transactionDepth == 1) {
dev->startTransaction();
resetStatus();
}
@@ -663,7 +636,7 @@ void QDataStream::startTransaction()
bool QDataStream::commitTransaction()
{
CHECK_STREAM_TRANSACTION_PRECOND(false)
- if (--d->transactionDepth == 0) {
+ if (--transactionDepth == 0) {
CHECK_STREAM_PRECOND(false)
if (q_status == ReadPastEnd) {
@@ -703,7 +676,7 @@ void QDataStream::rollbackTransaction()
setStatus(ReadPastEnd);
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -739,7 +712,7 @@ void QDataStream::abortTransaction()
q_status = ReadCorruptData;
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -762,13 +735,13 @@ bool QDataStream::isDeviceTransactionStarted() const
\internal
*/
-int QDataStream::readBlock(char *data, int len)
+qint64 QDataStream::readBlock(char *data, qint64 len)
{
// Disable reads on failure in transacted stream
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int readResult = dev->read(data, len);
+ const qint64 readResult = dev->read(data, len);
if (readResult != len)
setStatus(ReadPastEnd);
return readResult;
@@ -992,25 +965,12 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\overload
- \since 5.9
- Reads a floating point number from the stream into \a f,
- using the standard IEEE 754 format. Returns a reference to the
- stream.
-*/
-QDataStream &QDataStream::operator>>(qfloat16 &f)
-{
- return *this >> reinterpret_cast<qint16&>(f);
-}
+ Reads string \a s from the stream and returns a reference to the stream.
-
-/*!
- \overload
-
- Reads the '\\0'-terminated string \a s from the stream and returns
- a reference to the stream.
-
- The string is deserialized using \c{readBytes()}.
+ The string is deserialized using \c{readBytes()} where the serialization
+ format is a \c quint32 length specifier first, followed by that many bytes
+ of data. The resulting string is always '\\0'-terminated.
Space for the string is allocated using \c{new []} -- the caller must
destroy it with \c{delete []}.
@@ -1020,7 +980,7 @@ QDataStream &QDataStream::operator>>(qfloat16 &f)
QDataStream &QDataStream::operator>>(char *&s)
{
- uint len = 0;
+ qint64 len = 0;
return readBytes(s, len);
}
@@ -1054,7 +1014,29 @@ QDataStream &QDataStream::operator>>(char32_t &c)
return *this;
}
+#if QT_DEPRECATED_SINCE(6, 11)
+
+/*
+ \deprecated [6.11] Use an overload that takes qint64 length instead.
+*/
+QDataStream &QDataStream::readBytes(char *&s, uint &l)
+{
+ qint64 length = 0;
+ (void)readBytes(s, length);
+ if (length != qint64(uint(length))) {
+ setStatus(SizeLimitExceeded); // Cannot store length in l
+ delete[] s;
+ l = 0;
+ return *this;
+ }
+ l = uint(length);
+ return *this;
+}
+
+#endif // QT_DEPRECATED_SINCE(6, 11)
+
/*!
+ \since 6.7
Reads the buffer \a s from the stream and returns a reference to
the stream.
@@ -1064,30 +1046,40 @@ QDataStream &QDataStream::operator>>(char32_t &c)
The \a l parameter is set to the length of the buffer. If the
string read is empty, \a l is set to 0 and \a s is set to \nullptr.
- The serialization format is a quint32 length specifier first,
- then \a l bytes of data.
+ The serialization format is a length specifier first, then \a l
+ bytes of data. The length specifier is one quint32 if the version
+ is less than 6.7 or if the number of elements is less than 0xfffffffe
+ (2^32 -2), otherwise there is an extend value 0xfffffffe followed by
+ one quint64 with the actual value. In addition for containers that
+ support isNull(), it is encoded as a single quint32 with all bits
+ set and no data.
\sa readRawData(), writeBytes()
*/
-QDataStream &QDataStream::readBytes(char *&s, uint &l)
+QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
{
s = nullptr;
l = 0;
CHECK_STREAM_PRECOND(*this)
- quint32 len;
- *this >> len;
- if (len == 0)
+ qint64 length = readQSizeType(*this);
+ if (length == 0)
return *this;
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
+ qsizetype len = qsizetype(length);
+ if (length != len || length < 0) {
+ setStatus(SizeLimitExceeded); // Cannot store len
+ return *this;
+ }
+
+ qsizetype step = (dev->bytesAvailable() >= len) ? len : 1024 * 1024;
+ qsizetype allocated = 0;
char *prevBuf = nullptr;
char *curBuf = nullptr;
do {
- int blockSize = qMin(Step, len - allocated);
+ qsizetype blockSize = qMin(step, len - allocated);
prevBuf = curBuf;
curBuf = new char[allocated + blockSize + 1];
if (prevBuf) {
@@ -1099,11 +1091,12 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
return *this;
}
allocated += blockSize;
+ step *= 2;
} while (allocated < len);
s = curBuf;
s[len] = '\0';
- l = (uint)len;
+ l = len;
return *this;
}
@@ -1116,7 +1109,7 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
\sa readBytes(), QIODevice::read(), writeRawData()
*/
-int QDataStream::readRawData(char *s, int len)
+qint64 QDataStream::readRawData(char *s, qint64 len)
{
CHECK_STREAM_PRECOND(-1)
return readBlock(s, len);
@@ -1254,18 +1247,13 @@ QDataStream &QDataStream::operator<<(qint64 i)
*/
/*!
+ \fn QDataStream &QDataStream::operator<<(bool i)
+ \overload
+
Writes a boolean value, \a i, to the stream. Returns a reference
to the stream.
*/
-QDataStream &QDataStream::operator<<(bool i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!dev->putChar(qint8(i)))
- q_status = WriteFailed;
- return *this;
-}
-
/*!
\overload
@@ -1340,19 +1328,6 @@ QDataStream &QDataStream::operator<<(double f)
/*!
- \fn QDataStream &QDataStream::operator<<(qfloat16 f)
- \overload
- \since 5.9
-
- Writes a floating point number, \a f, to the stream using
- the standard IEEE 754 format. Returns a reference to the stream.
-*/
-QDataStream &QDataStream::operator<<(qfloat16 f)
-{
- return *this << reinterpret_cast<qint16&>(f);
-}
-
-/*!
\overload
Writes the '\\0'-terminated string \a s to the stream and returns a
@@ -1365,13 +1340,9 @@ QDataStream &QDataStream::operator<<(qfloat16 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;
}
@@ -1403,22 +1374,26 @@ QDataStream &QDataStream::operator<<(char32_t c)
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
- The \a len is serialized as a quint32, followed by \a len bytes
- from \a s. Note that the data is \e not encoded.
+ The \a len is serialized as a quint32 and an optional quint64,
+ followed by \a len bytes from \a s. Note that the data is
+ \e not encoded.
\sa writeRawData(), readBytes()
*/
-QDataStream &QDataStream::writeBytes(const char *s, uint len)
+QDataStream &QDataStream::writeBytes(const char *s, qint64 len)
{
+ if (len < 0) {
+ q_status = WriteFailed;
+ return *this;
+ }
CHECK_STREAM_WRITE_PRECOND(*this)
- *this << (quint32)len; // write length specifier
- if (len)
+ // Write length then, if any, content
+ if (writeQSizeType(*this, len) && len > 0)
writeRawData(s, len);
return *this;
}
-
/*!
Writes \a len bytes from \a s to the stream. Returns the
number of bytes actually written, or -1 on error.
@@ -1427,10 +1402,10 @@ QDataStream &QDataStream::writeBytes(const char *s, uint len)
\sa writeBytes(), QIODevice::write(), readRawData()
*/
-int QDataStream::writeRawData(const char *s, int len)
+qint64 QDataStream::writeRawData(const char *s, qint64 len)
{
CHECK_STREAM_WRITE_PRECOND(-1)
- int ret = dev->write(s, len);
+ qint64 ret = dev->write(s, len);
if (ret != len)
q_status = WriteFailed;
return ret;
@@ -1447,13 +1422,13 @@ int QDataStream::writeRawData(const char *s, int len)
\sa QIODevice::seek()
*/
-int QDataStream::skipRawData(int len)
+qint64 QDataStream::skipRawData(qint64 len)
{
CHECK_STREAM_PRECOND(-1)
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int skipResult = dev->skip(len);
+ const qint64 skipResult = dev->skip(len);
if (skipResult != len)
setStatus(ReadPastEnd);
return skipResult;