From 6dfbbc2a5435d2e9542e9cf2eb039147db0ff29b Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Mon, 6 Jan 2020 17:08:41 +0100 Subject: QV4: Support printing arrays with circular references Fixes: QTBUG-81105 Change-Id: Iaf0597cea3a5572f020c5f87a843774f33cc01fd Reviewed-by: Ulf Hermann --- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 13 +++++++++---- tests/auto/qml/qjsengine/tst_qjsengine.cpp | 13 +++++++++++++ 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 &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 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" -- cgit v1.2.3