From 3531f578d3b55fb151ae99112acdfd20228855fa Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 11 Nov 2021 15:45:46 -0800 Subject: QCborArray: allow large but in-range keys The 0x10000 limit should not apply if the key is a valid index in the array. Change-Id: I5e52dc5b093c43a3b678fffd16b6a2a5a69acd61 Reviewed-by: Edward Welbourne --- src/corelib/serialization/qcborvalue.cpp | 19 ++++++++++++++-- .../serialization/qcborvalue/tst_qcborvalue.cpp | 25 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index 8edcbfec1c..c0f8a9a40d 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -2215,6 +2215,21 @@ const QCborValue QCborValue::operator[](qint64 key) const return QCborValue(); } +static bool shouldArrayRemainArray(qint64 key, QCborValue::Type t, QCborContainerPrivate *container) +{ + constexpr qint64 LargeKey = 0x10000; + if (t != QCborValue::Array) + return false; + if (key < 0) + return false; // negative keys can't be an array index + if (key < LargeKey) + return true; + + // Only convert to map if key is greater than array size + 1 + qsizetype currentSize = container ? container->elements.size() : 0; + return key <= currentSize; +} + /*! \internal */ @@ -2369,7 +2384,7 @@ QCborValueRef QCborValue::operator[](QLatin1String key) */ QCborValueRef QCborValue::operator[](qint64 key) { - if (isArray() && key >= 0 && key < 0x10000) { + if (shouldArrayRemainArray(key, t, container)) { container = maybeGrow(container, key); return { container, qsizetype(key) }; } @@ -2898,7 +2913,7 @@ QCborValueRef QCborValueRef::operator[](QLatin1String key) QCborValueRef QCborValueRef::operator[](qint64 key) { auto &e = d->elements[i]; - if (e.type == QCborValue::Array && key >= 0 && key < 0x10000) { + if (shouldArrayRemainArray(key, e.type, e.container)) { e.container = maybeGrow(e.container, key); e.flags |= QtCbor::Element::IsContainer; return { e.container, qsizetype(key) }; diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index fcbe739a39..16884987f4 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -74,6 +74,7 @@ private slots: void arrayPrepend(); void arrayValueRef_data() { basics_data(); } void arrayValueRef(); + void arrayValueRefLargeKey(); void arrayInsertRemove_data() { basics_data(); } void arrayInsertRemove(); void arrayInsertTagged_data() { basics_data(); } @@ -1320,6 +1321,30 @@ void tst_QCborValue::arrayValueRef() iteratorCheck(a.constBegin()); } +void tst_QCborValue::arrayValueRefLargeKey() +{ + // make sure the access via QCborValue & QCborValueRef don't convert this + // array to a map + constexpr qsizetype LargeKey = 0x10000; + QCborArray a; + a[LargeKey + 1] = 123; + + QCborValue v(a); + QCOMPARE(qAsConst(v)[LargeKey], QCborValue()); + QCOMPARE(qAsConst(v)[LargeKey + 1], 123); + QCOMPARE(v[LargeKey], QCborValue()); + QCOMPARE(v[LargeKey + 1], 123); + QCOMPARE(v.type(), QCborValue::Array); + + QCborArray outer = { QCborValue(a) }; + QCborValueRef ref = outer[0]; + QCOMPARE(qAsConst(ref)[LargeKey], QCborValue()); + QCOMPARE(qAsConst(ref)[LargeKey + 1], 123); + QCOMPARE(ref[LargeKey], QCborValue()); + QCOMPARE(ref[LargeKey + 1], 123); + QCOMPARE(ref.type(), QCborValue::Array); +} + void tst_QCborValue::mapValueRef() { QFETCH(QCborValue, v); -- cgit v1.2.3