From 1e883cf9b56376084f3329811aa91f4887ef6fcb Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Thu, 24 Sep 2020 17:23:55 +0200 Subject: 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 --- src/corelib/kernel/qproperty.cpp | 8 ++++++++ src/corelib/kernel/qproperty_p.h | 11 +++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/corelib/kernel') 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 +#include 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; // 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) -- cgit v1.2.3