aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Weickelt <richard@weickelt.de>2018-05-15 12:28:41 +0200
committerRichard Weickelt <richard@weickelt.de>2018-05-18 09:29:26 +0000
commitd33d5a40483c6b56c3be19ce244f14938a5941a0 (patch)
treefdc7a803067b976ccf24470ee9288238806e1667
parent38dc69ae01d2ba733fb35f7c8d26500062858798 (diff)
Allow partial creation of more than 10 QQmlComponent instances
The recursion detection in QQmlComponent erroneously triggered when calling beginCreate() on >= 10 different instances. This may happen by intention and is not necessarily a sign of recursion. Since beginCreate() does never invoke a potentially nested Qt.createComponent(), but completeCreate() does, it is better to modify the creationDepth counter in completeCreate(). This also leads to simpler code. The test, however, can remain in beginCreate(). Task-number: QTBUG-47633 Change-Id: If413a8b08421d321d6a426ec16600996cb3f6ea1 Reviewed-by: Matthew Vogt <matthew.vogt@qinetic.com.au> Reviewed-by: Michael Brasser <michael.brasser@live.com> Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/qml/qqmlcomponent.cpp15
-rw-r--r--src/qml/qml/qqmlcomponent_p.h3
-rw-r--r--tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp24
3 files changed, 27 insertions, 15 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 1802932f45..22e20de8d7 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -845,13 +845,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;
- if (++creationDepth.localData() >= maxCreationDepth) {
+ if (creationDepth.localData() >= maxCreationDepth) {
qWarning("QQmlComponent: Component creation is recursing - aborting");
- --creationDepth.localData();
return nullptr;
}
- Q_ASSERT(creationDepth.localData() >= 1);
- depthIncreased = true;
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
@@ -875,10 +872,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
- } else {
- Q_ASSERT(creationDepth.localData() >= 1);
- --creationDepth.localData();
- depthIncreased = false;
}
return rv;
@@ -952,14 +945,10 @@ void QQmlComponent::completeCreate()
void QQmlComponentPrivate::completeCreate()
{
if (state.completePending) {
+ ++creationDepth.localData();
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
complete(ep, &state);
- }
-
- if (depthIncreased) {
- Q_ASSERT(creationDepth.localData() >= 1);
--creationDepth.localData();
- depthIncreased = false;
}
}
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 83af5074b8..9b2db4bccf 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -79,7 +79,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate()
- : progress(0.), start(-1), engine(nullptr), creationContext(nullptr), depthIncreased(false) {}
+ : progress(0.), start(-1), engine(nullptr), creationContext(nullptr) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
@@ -136,7 +136,6 @@ public:
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
- bool depthIncreased;
void clear();
diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
index 6a0dc28ca4..0263115db8 100644
--- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
+++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp
@@ -116,6 +116,7 @@ private slots:
void onDestructionCount();
void recursion();
void recursionContinuation();
+ void partialComponentCreation();
void callingContextForInitialProperties();
void relativeUrl_data();
void relativeUrl();
@@ -526,6 +527,29 @@ void tst_qqmlcomponent::recursionContinuation()
QVERIFY(object->property("success").toBool());
}
+void tst_qqmlcomponent::partialComponentCreation()
+{
+ const int maxCount = 17;
+ QQmlEngine engine;
+ QScopedPointer<QQmlComponent> components[maxCount];
+ QScopedPointer<QObject> objects[maxCount];
+ QQmlTestMessageHandler messageHandler;
+
+ QCOMPARE(engine.outputWarningsToStandardError(), true);
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i].reset(new QQmlComponent(&engine, testFileUrl("QtObjectComponent.qml")));
+ objects[i].reset(components[i]->beginCreate(engine.rootContext()));
+ QVERIFY(objects[i].isNull() == false);
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+
+ for (int i = 0; i < maxCount; i++) {
+ components[i]->completeCreate();
+ }
+ QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
+}
+
class CallingContextCheckingClass : public QObject
{
Q_OBJECT