summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2021-06-05 20:10:56 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2021-06-07 13:14:00 +0200
commitf6fb118c943ca4e54509b3c4c8aaafcdbb88f031 (patch)
treedf0b007b4c3cafdda59b4c8d02b7db2f93caf423 /src/corelib
parent0ebe5c9ef617b3bb889d159958bc634f4959bed0 (diff)
QProperty: Do not involve semi-destroyed QObjects in bindings
Once we're in ~QObject, only methods of QObject are still valid. Notably, no setter of any derived class is still valid. Thus, to be safe we must no longer react to binding changes of those properties. To ensure that this happens for QObjectCompatProperty properties, we explicitly clear the binding storage. Fixes a particles3d example crash. Change-Id: I10d2bfa5e96621ce039d751cffaf3ac41893623e Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qobject.cpp9
-rw-r--r--src/corelib/kernel/qobject_p.h2
-rw-r--r--src/corelib/kernel/qproperty.cpp6
-rw-r--r--src/corelib/kernel/qproperty.h2
4 files changed, 19 insertions, 0 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index f3ea22d25d..fafcd38417 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -943,6 +943,11 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
Q_TRACE(QObject_ctor, this);
}
+void QObjectPrivate::clearBindingStorage()
+{
+ bindingStorage.clear();
+}
+
/*!
Destroys the object, deleting all its child objects.
@@ -973,6 +978,10 @@ QObject::~QObject()
d->wasDeleted = true;
d->blockSig = 0; // unblock signals so we always emit destroyed()
+ // If we reached this point, we need to clear the binding data
+ // as the corresponding properties are no longer useful
+ d->clearBindingStorage();
+
QtSharedPointer::ExternalRefCountData *sharedRefcount = d->sharedRefcount.loadRelaxed();
if (sharedRefcount) {
if (sharedRefcount->strongref.loadRelaxed() > 0) {
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 4f38796c81..6d5044e99c 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -326,6 +326,8 @@ public:
QObjectPrivate(int version = QObjectPrivateVersion);
virtual ~QObjectPrivate();
void deleteChildren();
+ // used to clear binding storage early in ~QObject
+ void clearBindingStorage();
inline void checkForIncompatibleLibraryVersion(int version) const;
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index 43fc84159a..0df73ad639 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -2138,6 +2138,12 @@ QBindingStorage::~QBindingStorage()
QBindingStoragePrivate(d).destroy();
}
+void QBindingStorage::clear()
+{
+ QBindingStoragePrivate(d).destroy();
+ d = nullptr;
+}
+
// ### Unused, retained for BC with 6.0
void QBindingStorage::maybeUpdateBindingAndRegister_helper(const QUntypedPropertyData *data) const
{
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index 5deb8fa9b7..9c002f378f 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -945,6 +945,7 @@ class Q_CORE_EXPORT QBindingStorage
template<typename Class, typename T, auto Offset, auto Setter, auto Signal>
friend class QObjectCompatProperty;
+ friend class QObjectPrivate;
public:
QBindingStorage();
~QBindingStorage();
@@ -973,6 +974,7 @@ public:
return bindingData_helper(data, create);
}
private:
+ void clear();
void registerDependency_helper(const QUntypedPropertyData *data) const;
// ### Unused, but keep for BC
void maybeUpdateBindingAndRegister_helper(const QUntypedPropertyData *data) const;