summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2020-09-24 17:23:55 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2020-09-28 09:11:16 +0200
commit1e883cf9b56376084f3329811aa91f4887ef6fcb (patch)
treec12a32fcc3cea219abd1bb152ef108f686a03eb1 /src/corelib/kernel
parentde52ad0a0f31654ff86e77fc4545335e9651d3f2 (diff)
Prevent endless markDirtyAndNotifyObservers <-> notify loop
Before we had the option of eager evaluation, we were able to use the dirty flag to detect whether we are recursing. However, eager properties will lead to a evaluateIfDirtyAndReturnTrueIfValueChanged call, and that in turn will clear the dirty flag. Introduce a new member to detect that situation, and set the bindings error state to BindingLoop if we detect that kind of loop. Change-Id: If40b93221848bd9e9422502318d992fad95b0b74 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qproperty.cpp8
-rw-r--r--src/corelib/kernel/qproperty_p.h11
2 files changed, 17 insertions, 2 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 72f74ac1e8..81871587e8 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -41,6 +41,7 @@
#include "qproperty_p.h"
#include <qscopedvaluerollback.h>
+#include <QScopeGuard>
QT_BEGIN_NAMESPACE
@@ -82,6 +83,13 @@ void QPropertyBindingPrivate::markDirtyAndNotifyObservers()
if (dirty)
return;
dirty = true;
+ if (eagerlyUpdating) {
+ error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
+ return;
+ }
+
+ eagerlyUpdating = true;
+ QScopeGuard guard([&](){eagerlyUpdating = false;});
if (requiresEagerEvaluation()) {
// these are compat properties that we will need to evaluate eagerly
evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index c5c74147c1..999760ec86 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -163,10 +163,15 @@ private:
using ObserverArray = std::array<QPropertyObserver, 4>;
// QSharedData is 4 bytes. Use the padding for the bools as we need 8 byte alignment below.
+
+ // a dependent property has changed, and the binding needs to be reevaluated on access
bool dirty = false;
+ // used to detect binding loops for lazy evaluated properties
bool updating = false;
bool hasStaticObserver = false;
- bool hasBindingWrapper = false;
+ bool hasBindingWrapper:1;
+ // used to detect binding loops for eagerly evaluated properties
+ bool eagerlyUpdating:1;
QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction;
@@ -192,7 +197,9 @@ public:
QPropertyBindingPrivate(QMetaType metaType, QUntypedPropertyBinding::BindingEvaluationFunction evaluationFunction,
const QPropertyBindingSourceLocation &location)
- : evaluationFunction(std::move(evaluationFunction))
+ : hasBindingWrapper(false)
+ , eagerlyUpdating(false)
+ , evaluationFunction(std::move(evaluationFunction))
, inlineDependencyObservers() // Explicit initialization required because of union
, location(location)
, metaType(metaType)