summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJüri Valdmann <juri.valdmann@qt.io>2018-07-26 16:03:50 +0200
committerJüri Valdmann <juri.valdmann@qt.io>2018-08-06 07:48:50 +0000
commite0d0fd38d0e613930dd7185a0d4a2446fb75e091 (patch)
treead47ba70159924180bb8b732f1acd95a5ba6a145
parentc712aa1897dc1c84dd3f5bae83120ba4411a6f25 (diff)
QJsonDocument: Make emptyObject an object
A default-constructed QJsonObject has no data payload, it is only a pair of null pointers. So, when it becomes necessary to 'materialize' such an object, a special global emptyObject constant is used as the substitute payload. There is a small problem with this global constant though, namely that it's is_object flag is unset. In other words, the emptyObject is not an object, but an array. Fix by setting the is_object flag on emptyObject. The example code in the bug report QJsonObject parent; QJsonObject child; parent["child"] = child; // 1 child = parent["child"].toObject(); // 2 child["test"] = "test"; // 3 runs into this problem on line 1. Inserting the default-constructed child means inserting a copy of emptyObject. On line 2 a pointer to this copy of emptyObject is retrieved and cast to an object. But it's not an object, it's an array, so things go wrong hereafter. Specifically, on line 3, two inserts are performed, one from operator[] and one from operator=. Each insert increments a compaction counter. The second insert triggers compaction (QJsonObject::insert calls Value::requiredStorage calls Data::compact) and compaction branches based on the is_object flag. Replacing line 3 with child.insert("test", "test"); causes the example to appear to work since compaction is not triggered and the JSON serializer does not look at the is_object flag. Still, any further insert() calls would trigger compaction and memory corruption. Task-number: QTBUG-69626 Change-Id: I8bd5174dce95998bac479c4b4ffea70bca1a4d04 Reviewed-by: Lars Knoll <lars.knoll@qt.io> (cherry picked from commit f43e947dc405b6a2324656f631c804db8e8dec3d)
-rw-r--r--src/corelib/json/qjson.cpp2
-rw-r--r--tests/auto/corelib/json/tst_qtjson.cpp2
2 files changed, 3 insertions, 1 deletions
diff --git a/src/corelib/json/qjson.cpp b/src/corelib/json/qjson.cpp
index 31260ef5fd..317100511d 100644
--- a/src/corelib/json/qjson.cpp
+++ b/src/corelib/json/qjson.cpp
@@ -52,7 +52,7 @@ namespace QJsonPrivate
#endif
static const Base emptyArray = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
-static const Base emptyObject = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { 0 }, { 0 } };
+static const Base emptyObject = { { Q_TO_LITTLE_ENDIAN(sizeof(Base)) }, { Q_TO_LITTLE_ENDIAN(1u) }, { 0 } };
void Data::compact()
diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp
index 275e6bfeb1..824a6188f7 100644
--- a/tests/auto/corelib/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/json/tst_qtjson.cpp
@@ -640,6 +640,7 @@ void tst_QtJson::testArrayNestedEmpty()
object.insert("inner", inner);
QJsonValue val = object.value("inner");
QJsonArray value = object.value("inner").toArray();
+ QVERIFY(QJsonDocument(value).isArray());
QCOMPARE(value.size(), 0);
QCOMPARE(value, inner);
QCOMPARE(value.size(), 0);
@@ -658,6 +659,7 @@ void tst_QtJson::testObjectNestedEmpty()
object.insert("inner", inner);
object.insert("inner2", inner2);
QJsonObject value = object.value("inner").toObject();
+ QVERIFY(QJsonDocument(value).isObject());
QCOMPARE(value.size(), 0);
QCOMPARE(value, inner);
QCOMPARE(value.size(), 0);