Avoid misleading bindingStatus

Set it to nullptr on clear, and deal with possibly null bindingStatus.

Task-number: QTBUG-101177
Task-number: QTBUG-102403
Pick-to: 6.4
Change-Id: I66cb4d505a4f7b377dc90b45ac13834fca19d399
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Allan Sandfeld Jensen 2022-06-17 12:36:21 +02:00
parent 903bde19a4
commit 0bd2876275
5 changed files with 42 additions and 5 deletions

View File

@ -55,7 +55,7 @@ public:
void registerDependency(const QUntypedPropertyData *data) const
{
if (!bindingStatus->currentlyEvaluatingBinding)
if (!bindingStatus || !bindingStatus->currentlyEvaluatingBinding)
return;
registerDependency_helper(data);
}

View File

@ -1873,9 +1873,9 @@ void QObjectPrivate::moveToThread_helper()
Q_Q(QObject);
QEvent e(QEvent::ThreadChange);
QCoreApplication::sendEvent(q, &e);
bindingStorage.clear();
for (int i = 0; i < children.size(); ++i) {
QObject *child = children.at(i);
child->d_func()->bindingStorage.clear();
child->d_func()->moveToThread_helper();
}
}

View File

@ -2193,6 +2193,7 @@ void QBindingStorage::clear()
{
QBindingStoragePrivate(d).destroy();
d = nullptr;
bindingStatus = nullptr;
}
void QBindingStorage::registerDependency_helper(const QUntypedPropertyData *data) const

View File

@ -442,7 +442,7 @@ class QObjectCompatProperty : public QPropertyData<T>
}
bool inBindingWrapper(const QBindingStorage *storage) const
{
return storage->bindingStatus->currentCompatProperty
return storage->bindingStatus && storage->bindingStatus->currentCompatProperty
&& QtPrivate::isPropertyInBindingWrapper(this);
}
@ -467,7 +467,7 @@ public:
{
const QBindingStorage *storage = qGetBindingStorage(owner());
// make sure we don't register this binding as a dependency to itself
if (storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
if (storage->bindingStatus && storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
storage->registerDependency_helper(this);
return this->val;
}

View File

@ -79,6 +79,7 @@ private slots:
void noFakeDependencies();
void threadSafety();
void threadSafety2();
void bindablePropertyWithInitialization();
void noDoubleNotification();
@ -1694,7 +1695,7 @@ void tst_QProperty::threadSafety()
auto child1 = new ThreadSafetyTester(obj1);
obj1->moveToThread(&workerThread);
const auto mainThreadBindingStatus = QtPrivate::getBindingStatus({});
QCOMPARE(qGetBindingStorage(child1)->status({}), mainThreadBindingStatus);
QCOMPARE(qGetBindingStorage(child1)->status({}), nullptr);
workerThread.start();
bool correctStatus = false;
@ -1743,6 +1744,41 @@ void tst_QProperty::threadSafety()
QCOMPARE(obj3->objectName(), "moved again");
}
class QPropertyUsingThread : public QThread
{
public:
QPropertyUsingThread(QObject **dest, QThread *destThread) : dest(dest), destThread(destThread) {}
void run() override
{
scopedObj1.reset(new ThreadSafetyTester());
scopedObj1->setObjectName("test");
QObject *child = new ThreadSafetyTester(scopedObj1.get());
child->setObjectName("child");
exec();
scopedObj1->moveToThread(destThread);
*dest = scopedObj1.release();
}
std::unique_ptr<ThreadSafetyTester> scopedObj1;
QObject **dest;
QThread *destThread;
};
void tst_QProperty::threadSafety2()
{
std::unique_ptr<QObject> movedObj;
{
QObject *tmp = nullptr;
QPropertyUsingThread workerThread(&tmp, QThread::currentThread());
workerThread.start();
workerThread.quit();
workerThread.wait();
movedObj.reset(tmp);
}
QCOMPARE(movedObj->objectName(), "test");
QCOMPARE(movedObj->children().first()->objectName(), "child");
}
struct CustomType
{
CustomType() = default;