diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-09-25 15:45:28 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-09-29 20:32:32 +0200 |
commit | 6b4e0c5803b4b8b4396791ba436d9692195993d6 (patch) | |
tree | a822ce5bfcd8c44f83f12dead974cc4f4e1d153f | |
parent | 7a41b928d415b69635abeff13a3a6d205386652f (diff) |
QProperty: fix QBindingStoragePrivate::reallocate related code
In the internal hash map implementation, we have to ensure that the
index is in the interval [0, size - 1].
Moreover, in setBinding we have to refetch the binding storage in case a
reallocation happened.
Change-Id: I11c6264f16537699c8908b647e2355a39ce87648
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/corelib/kernel/qproperty.cpp | 3 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 36 |
3 files changed, 41 insertions, 1 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 81871587e8..4fdf0d8100 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -1388,7 +1388,8 @@ struct QBindingStoragePrivate for (size_t i = 0; i < d->size; ++i, ++p) { if (p->data) { Pair *pp = pairs(newData); - size_t index = qHash(p->data); + Q_ASSERT(newData->size && (newData->size & (newData->size - 1)) == 0); // size is a power of two + size_t index = qHash(p->data) & (newData->size - 1); while (pp[index].data) { ++index; if (index == newData->size) diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 999760ec86..614756a670 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -397,6 +397,9 @@ public: { QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true); QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, nullptr, bindingWrapper)); + // refetch the binding data, as the eager evaluation in setBinding() above could cause a reallocation + // in the binding storage + bd = qGetBindingStorage(owner())->bindingData(this); notify(bd); return static_cast<QPropertyBinding<T> &>(oldBinding); } diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 0394e9ccf7..d71053ff04 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -60,6 +60,7 @@ private slots: void bindingSourceLocation(); void bindingError(); void bindingLoop(); + void realloc(); void changePropertyFromWithinChangeHandler(); void changePropertyFromWithinChangeHandlerThroughDependency(); void changePropertyFromWithinChangeHandler2(); @@ -567,6 +568,41 @@ void tst_QProperty::bindingLoop() QCOMPARE(tester.bindableEagerProp2().binding().error().type(), QPropertyBindingError::BindingLoop); } +class ReallocTester : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop1 READ prop1 WRITE setProp1 BINDABLE bindableProp1) + Q_PROPERTY(int prop2 READ prop2 WRITE setProp2 BINDABLE bindableProp2) + Q_PROPERTY(int prop3 READ prop3 WRITE setProp3 BINDABLE bindableProp3) + Q_PROPERTY(int prop4 READ prop4 WRITE setProp4 BINDABLE bindableProp4) + Q_PROPERTY(int prop5 READ prop5 WRITE setProp5 BINDABLE bindableProp5) +public: + ReallocTester(QObject *parent = nullptr) : QObject(parent) {} + + +#define GEN(N) \ + int prop##N() {return propData##N.value();} \ + void setProp##N(int i) { propData##N = i; } \ + QBindable<int> bindableProp##N() {return QBindable<int>(&propData##N);} \ + Q_OBJECT_COMPAT_PROPERTY(ReallocTester, int, propData##N, &ReallocTester::setProp##N) + GEN(1) + GEN(2) + GEN(3) + GEN(4) + GEN(5) +#undef GEN +}; + +void tst_QProperty::realloc() +{ + ReallocTester tester; + tester.bindableProp1().setBinding([&](){return tester.prop5();}); + tester.bindableProp2().setBinding([&](){return tester.prop5();}); + tester.bindableProp3().setBinding([&](){return tester.prop5();}); + tester.bindableProp4().setBinding([&](){return tester.prop5();}); + tester.bindableProp5().setBinding([&]() -> int{return 42;}); +}; + void tst_QProperty::changePropertyFromWithinChangeHandler() { QProperty<int> property(100); |