From cc46992fbb94f1775ac22aa23b42d76f810a5913 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 21 Nov 2017 12:18:56 -0600 Subject: Fix issue with circular singleton instantiations While a recursion check exists and works, it can lead to instanting the same singleton multiple times (leaking all but one copy). Change-Id: Icf342aad71c5cb225488262341517d95786e1f84 Reviewed-by: Erik Verbruggen Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlmetatype.cpp | 4 +++- tests/auto/qml/qqmllanguage/data/circularSingleton.qml | 6 ++++++ .../data/singleton/circular/MySingleton.qml | 12 ++++++++++++ .../qml/qqmllanguage/data/singleton/circular/qmldir | 1 + tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/auto/qml/qqmllanguage/data/circularSingleton.qml create mode 100644 tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml create mode 100644 tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 8e6be538ef..0f388cf7b7 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -274,8 +274,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) QQmlData::ensurePropertyCache(e, o); } else if (!url.isEmpty() && !qobjectApi(e)) { QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); - QObject *o = component.create(); + QObject *o = component.beginCreate(e->rootContext()); setQObjectApi(e, o); + if (o) + component.completeCreate(); } v4->popContext(); } diff --git a/tests/auto/qml/qqmllanguage/data/circularSingleton.qml b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml new file mode 100644 index 0000000000..e569111956 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml @@ -0,0 +1,6 @@ +import QtQuick 2.10 +import "singleton/circular" + +QtObject { + property int value: MySingleton.value +} diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml new file mode 100644 index 0000000000..1253018789 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml @@ -0,0 +1,12 @@ +pragma Singleton +import QtQuick 2.10 + +QtObject { + enum MyEnum { + Value0, + Value1, + Value2 + } + + property int value: MySingleton.Value2 +} diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir new file mode 100644 index 0000000000..3bc50738dd --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir @@ -0,0 +1 @@ +singleton MySingleton MySingleton.qml diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 21efb0336d..7fb4c809f7 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -240,6 +240,7 @@ private slots: void compositeSingletonJavaScriptPragma(); void compositeSingletonSelectors(); void compositeSingletonRegistered(); + void compositeSingletonCircular(); void customParserBindingScopes(); void customParserEvaluateEnum(); @@ -4211,6 +4212,22 @@ void tst_qqmllanguage::compositeSingletonRegistered() verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755); } +void tst_qqmllanguage::compositeSingletonCircular() +{ + QQmlComponent component(&engine, testFile("circularSingleton.qml")); + VERIFY_ERRORS(0); + + QQmlTestMessageHandler messageHandler; + + QObject *o = component.create(); + QVERIFY(o != 0); + + // ensure we aren't hitting the recursion warning + QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString())); + + QCOMPARE(o->property("value").toInt(), 2); +} + void tst_qqmllanguage::customParserBindingScopes() { QQmlComponent component(&engine, testFile("customParserBindingScopes.qml")); -- cgit v1.2.3