diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2020-03-27 01:00:18 +0100 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2020-03-27 09:23:33 +0100 |
commit | 4752bd7718250dec5b725b9ba2c6f4bc88743ba6 (patch) | |
tree | 6563c20d69c982d476b1b25366cb550f3ef42354 /src/corelib/serialization/qcborvalue.cpp | |
parent | 96de59d7c1068022dbb590d7abbdcf6eaf5d0566 (diff) | |
parent | f581b041199ba7c825fbffd9110727360d1f2668 (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts:
src/corelib/serialization/qcborvalue.cpp
Change-Id: I539d8cae5fd413b8a6c9c5d8a6364c79c8133a0a
Diffstat (limited to 'src/corelib/serialization/qcborvalue.cpp')
-rw-r--r-- | src/corelib/serialization/qcborvalue.cpp | 109 |
1 files changed, 65 insertions, 44 deletions
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index db2840704c..98161094ae 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -844,11 +844,6 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d) return QCborValue::Tag; } -#if QT_CONFIG(cborstreamreader) -// in qcborstream.cpp -extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error); -#endif - #if QT_CONFIG(cborstreamwriter) static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt) { @@ -1462,23 +1457,59 @@ static Element decodeBasicValueFromCbor(QCborStreamReader &reader) return e; } -static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader) +static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth) { - auto d = new QCborContainerPrivate; - d->ref.storeRelaxed(1); - d->decodeFromCbor(reader); + if (Q_UNLIKELY(remainingRecursionDepth == 0)) { + QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep }); + return nullptr; + } + + QCborContainerPrivate *d = nullptr; + int mapShift = reader.isMap() ? 1 : 0; + if (reader.isLengthKnown()) { + quint64 len = reader.length(); + + // Clamp allocation to 1M elements (avoids crashing due to corrupt + // stream or loss of precision when converting from quint64 to + // QVector::size_type). + len = qMin(len, quint64(1024 * 1024 - 1)); + if (len) { + d = new QCborContainerPrivate; + d->ref.storeRelaxed(1); + d->elements.reserve(qsizetype(len) << mapShift); + } + } else { + d = new QCborContainerPrivate; + d->ref.storeRelaxed(1); + } + + reader.enterContainer(); + if (reader.lastError() != QCborError::NoError) + return d; + + while (reader.hasNext() && reader.lastError() == QCborError::NoError) + d->decodeValueFromCbor(reader, remainingRecursionDepth - 1); + + if (reader.lastError() == QCborError::NoError) + reader.leaveContainer(); + return d; } -static QCborValue taggedValueFromCbor(QCborStreamReader &reader) +static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth) { + if (Q_UNLIKELY(remainingRecursionDepth == 0)) { + QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep }); + return QCborValue::Invalid; + } + auto d = new QCborContainerPrivate; d->append(reader.toTag()); reader.next(); if (reader.lastError() == QCborError::NoError) { // decode tagged value - d->decodeValueFromCbor(reader); + d->decodeValueFromCbor(reader, remainingRecursionDepth - 1); } QCborValue::Type type; @@ -1494,6 +1525,13 @@ static QCborValue taggedValueFromCbor(QCborStreamReader &reader) return QCborContainerPrivate::makeValue(type, -1, d); } +// in qcborstream.cpp +extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error); +inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error) +{ + qt_cbor_stream_set_error(reader.d.data(), error); +} + void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) { auto addByteData_local = [this](QByteArray::size_type len) -> qint64 { @@ -1538,7 +1576,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) return; // error if (len != rawlen) { // truncation - qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); + setErrorInReader(reader, { QCborError::DataTooLarge }); return; } @@ -1548,7 +1586,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) e.value = addByteData_local(len); if (e.value < 0) { // overflow - qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); + setErrorInReader(reader, { QCborError::DataTooLarge }); return; } } @@ -1562,7 +1600,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) auto utf8result = QUtf8::isValidUtf8(dataPtr() + data.size() - len, len); if (!utf8result.isValidUtf8) { r.status = QCborStreamReader::Error; - qt_cbor_stream_set_error(reader.d.data(), { QCborError::InvalidUtf8String }); + setErrorInReader(reader, { QCborError::InvalidUtf8String }); break; } isAscii = isAscii && utf8result.isValidAscii; @@ -1586,7 +1624,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) // error r.status = QCborStreamReader::Error; - qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge }); + setErrorInReader(reader, { QCborError::DataTooLarge }); } if (r.status == QCborStreamReader::Error) { @@ -1612,9 +1650,10 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader) elements.append(e); } -void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader) +void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth) { - switch (reader.type()) { + QCborStreamReader::Type t = reader.type(); + switch (t) { case QCborStreamReader::UnsignedInteger: case QCborStreamReader::NegativeInteger: case QCborStreamReader::SimpleType: @@ -1631,37 +1670,17 @@ void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader) case QCborStreamReader::Array: case QCborStreamReader::Map: + return append(makeValue(t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, -1, + createContainerFromCbor(reader, remainingRecursionDepth), + MoveContainer)); + case QCborStreamReader::Tag: - return append(QCborValue::fromCbor(reader)); + return append(taggedValueFromCbor(reader, remainingRecursionDepth)); case QCborStreamReader::Invalid: return; // probably a decode error } } - -void QCborContainerPrivate::decodeFromCbor(QCborStreamReader &reader) -{ - int mapShift = reader.isMap() ? 1 : 0; - if (reader.isLengthKnown()) { - quint64 len = reader.length(); - - // Clamp allocation to 1M elements (avoids crashing due to corrupt - // stream or loss of precision when converting from quint64 to - // QVector::size_type). - len = qMin(len, quint64(1024 * 1024 - 1)); - elements.reserve(qsizetype(len) << mapShift); - } - - reader.enterContainer(); - if (reader.lastError() != QCborError::NoError) - return; - - while (reader.hasNext() && reader.lastError() == QCborError::NoError) - decodeValueFromCbor(reader); - - if (reader.lastError() == QCborError::NoError) - reader.leaveContainer(); -} #endif // QT_CONFIG(cborstreamreader) /*! @@ -2363,6 +2382,8 @@ QCborValueRef QCborValue::operator[](qint64 key) } #if QT_CONFIG(cborstreamreader) +enum { MaximumRecursionDepth = 1024 }; + /*! Decodes one item from the CBOR stream found in \a reader and returns the equivalent representation. This function is recursive: if the item is a map @@ -2423,12 +2444,12 @@ QCborValue QCborValue::fromCbor(QCborStreamReader &reader) case QCborStreamReader::Map: result.n = -1; result.t = reader.isArray() ? Array : Map; - result.container = createContainerFromCbor(reader); + result.container = createContainerFromCbor(reader, MaximumRecursionDepth); break; // tag case QCborStreamReader::Tag: - result = taggedValueFromCbor(reader); + result = taggedValueFromCbor(reader, MaximumRecursionDepth); break; } |