aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-01-06 17:08:41 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2020-01-07 14:11:49 +0100
commit6dfbbc2a5435d2e9542e9cf2eb039147db0ff29b (patch)
tree9c951d175db4c52ee92bf2c47b79242cd3d12604
parent49cf23bd2a14e2ca7236b261d7960588f07f5a0b (diff)
QV4: Support printing arrays with circular references
Fixes: QTBUG-81105 Change-Id: Iaf0597cea3a5572f020c5f87a843774f33cc01fd Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp13
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp13
2 files changed, 22 insertions, 4 deletions
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index d634a48443..f5e723419e 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1553,11 +1553,12 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
-static QString serializeArray(Object *array, ExecutionEngine *v4) {
+static QString serializeArray(Object *array, ExecutionEngine *v4, QSet<QV4::Heap::Object *> &alreadySeen) {
Scope scope(v4);
ScopedValue val(scope);
QString result;
+ alreadySeen.insert(array->d());
result += QLatin1Char('[');
const uint length = array->getLength();
for (uint i = 0; i < length; ++i) {
@@ -1565,12 +1566,15 @@ static QString serializeArray(Object *array, ExecutionEngine *v4) {
result += QLatin1Char(',');
val = array->get(i);
if (val->isManaged() && val->managed()->isArrayLike())
- result += serializeArray(val->objectValue(), v4);
+ if (!alreadySeen.contains(val->objectValue()->d()))
+ result += serializeArray(val->objectValue(), v4, alreadySeen);
+ else
+ result += QLatin1String("[Circular]");
else
result += val->toQStringNoThrow();
}
result += QLatin1Char(']');
-
+ alreadySeen.remove(array->d());
return result;
};
@@ -1600,8 +1604,9 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *, cons
if (i != start)
result.append(QLatin1Char(' '));
+ QSet<QV4::Heap::Object *> alreadySeenElements;
if (argv[i].isManaged() && argv[i].managed()->isArrayLike())
- result.append(serializeArray(argv[i].objectValue(), v4));
+ result.append(serializeArray(argv[i].objectValue(), v4, alreadySeenElements));
else
result.append(argv[i].toQStringNoThrow());
}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 56d2ce8730..b9df69d2db 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -258,6 +258,7 @@ private slots:
void tostringRecursionCheck();
void arrayIncludesWithLargeArray();
+ void printCircularArray();
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
@@ -5054,6 +5055,18 @@ void tst_QJSEngine::arrayIncludesWithLargeArray()
QCOMPARE(value.toBool(), false);
}
+void tst_QJSEngine::printCircularArray()
+{
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::ConsoleExtension);
+ QTest::ignoreMessage(QtMsgType::QtDebugMsg, "[[Circular]]");
+ auto value = engine.evaluate(R"js(
+ let v1 = []
+ v1.push(v1)
+ console.log(v1)
+ )js");
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"