QProperty: Destroy binding when refcount is 0
This has to be done from all places where we deref it. Otherwise we leak memory. Pick-to: 6.6 6.5 Fixes: QTBUG-116086 Change-Id: I57307ac746205578a920d2bb1e159b66ebd9b2cc Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 717dc9450ffc13ef8209a10073552ac4574a4160) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
fb5ff98d32
commit
933d695ecb
@ -753,13 +753,6 @@ void QPropertyObserverPointer::setChangeHandler(QPropertyObserver::ChangeHandler
|
|||||||
ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
|
ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QPropertyObserverPointer::setBindingToNotify(QPropertyBindingPrivate *binding)
|
|
||||||
{
|
|
||||||
Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
|
|
||||||
ptr->binding = binding;
|
|
||||||
ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
The same as setBindingToNotify, but assumes that the tag is already correct.
|
The same as setBindingToNotify, but assumes that the tag is already correct.
|
||||||
|
@ -143,7 +143,13 @@ struct QPropertyObserverPointer
|
|||||||
unlink_common();
|
unlink_common();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBindingToNotify(QPropertyBindingPrivate *binding);
|
void setBindingToNotify(QPropertyBindingPrivate *binding)
|
||||||
|
{
|
||||||
|
Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
|
||||||
|
ptr->binding = binding;
|
||||||
|
ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
|
||||||
|
}
|
||||||
|
|
||||||
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
|
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
|
||||||
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
|
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
|
||||||
|
|
||||||
@ -941,7 +947,15 @@ QBindingObserverPtr::QBindingObserverPtr(QPropertyObserver *observer) noexcept :
|
|||||||
QPropertyObserverPointer{d}.binding()->addRef();
|
QPropertyObserverPointer{d}.binding()->addRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
QBindingObserverPtr::~QBindingObserverPtr() { if (d) QPropertyObserverPointer{d}.binding()->deref(); }
|
QBindingObserverPtr::~QBindingObserverPtr()
|
||||||
|
{
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QPropertyBindingPrivate *bindingPrivate = binding();
|
||||||
|
if (!bindingPrivate->deref())
|
||||||
|
QPropertyBindingPrivate::destroyAndFreeMemory(bindingPrivate);
|
||||||
|
}
|
||||||
|
|
||||||
QPropertyBindingPrivate *QBindingObserverPtr::binding() const noexcept { return QPropertyObserverPointer{d}.binding(); }
|
QPropertyBindingPrivate *QBindingObserverPtr::binding() const noexcept { return QPropertyObserverPointer{d}.binding(); }
|
||||||
|
|
||||||
|
@ -108,6 +108,8 @@ private slots:
|
|||||||
|
|
||||||
void propertyAdaptorBinding();
|
void propertyAdaptorBinding();
|
||||||
void propertyUpdateViaSignaledProperty();
|
void propertyUpdateViaSignaledProperty();
|
||||||
|
|
||||||
|
void derefFromObserver();
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -315,6 +317,7 @@ void tst_QProperty::bindingAfterUse()
|
|||||||
|
|
||||||
void tst_QProperty::bindingFunctionDtorCalled()
|
void tst_QProperty::bindingFunctionDtorCalled()
|
||||||
{
|
{
|
||||||
|
DtorCounter::counter = 0;
|
||||||
DtorCounter dc;
|
DtorCounter dc;
|
||||||
{
|
{
|
||||||
QProperty<int> prop;
|
QProperty<int> prop;
|
||||||
@ -2531,6 +2534,47 @@ void tst_QProperty::propertyUpdateViaSignaledProperty()
|
|||||||
QCOMPARE(o.bindable2(), 36);
|
QCOMPARE(o.bindable2(), 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QProperty::derefFromObserver()
|
||||||
|
{
|
||||||
|
int triggered = 0;
|
||||||
|
QProperty<int> source(11);
|
||||||
|
|
||||||
|
DtorCounter::counter = 0;
|
||||||
|
DtorCounter dc;
|
||||||
|
|
||||||
|
QProperty<int> target([&triggered, &source, dc]() mutable {
|
||||||
|
dc.shouldIncrement = true;
|
||||||
|
return ++triggered + source.value();
|
||||||
|
});
|
||||||
|
QCOMPARE(triggered, 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto propObserver = std::make_unique<QPropertyObserver>();
|
||||||
|
QPropertyObserverPointer propObserverPtr { propObserver.get() };
|
||||||
|
propObserverPtr.setBindingToNotify(QPropertyBindingPrivate::get(target.binding()));
|
||||||
|
|
||||||
|
QBindingObserverPtr bindingPtr(propObserver.get());
|
||||||
|
|
||||||
|
QCOMPARE(triggered, 1);
|
||||||
|
source = 25;
|
||||||
|
QCOMPARE(triggered, 2);
|
||||||
|
QCOMPARE(target, 27);
|
||||||
|
|
||||||
|
target.setBinding([]() { return 8; });
|
||||||
|
QCOMPARE(target, 8);
|
||||||
|
|
||||||
|
// The QBindingObserverPtr still holds on to the binding.
|
||||||
|
QCOMPARE(dc.counter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The binding is actually gone now.
|
||||||
|
QCOMPARE(dc.counter, 1);
|
||||||
|
|
||||||
|
source = 26;
|
||||||
|
QCOMPARE(triggered, 2);
|
||||||
|
QCOMPARE(target, 8);
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QProperty);
|
QTEST_MAIN(tst_QProperty);
|
||||||
|
|
||||||
#undef QT_SOURCE_LOCATION_NAMESPACE
|
#undef QT_SOURCE_LOCATION_NAMESPACE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user