summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2022-08-16 15:32:58 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2022-08-20 23:12:37 +0200
commit580e0527ebcbc8eb74b17a536d64b3217b8c1f22 (patch)
treed8a14fc47dd30cf0a7e1d8855ecc9e56294a4f44 /tests
parent485c7a825628ac4f504cf7ce58fff9cc656aabce (diff)
Don't access QObjectPrivate::declarativeData unguarded
The QObjectPrivate::declarativeData member is stored in a union with currentChildBeingDeleted. The QObject destructor always sets the currentChildBeingDeleted member of the union. It also sets the isDeletingChildren bool, which is the only way to find out which union member we can safely access. While the QObject destructor is deleting children and isDeletingChildren is set, we must not access the declarativeData member of the union. Add a test case that initializes the function pointers for the declarative handlers and constructs a situation where an object emits a signal while it is destroying children. Fixes: QTBUG-105286 Change-Id: Iea5ba2f7843b6926a8d157be166e6044d98d6c02 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> (cherry picked from commit 3be99799a675a631c67e05897383af9abbc377b3) Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp73
1 files changed, 73 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 25da013292..471d73e512 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -158,6 +158,7 @@ private slots:
void nullReceiver();
void functorReferencesConnection();
void disconnectDisconnects();
+ void declarativeData();
};
struct QObjectCreatedOnShutdown
@@ -7689,5 +7690,77 @@ void tst_QObject::disconnectDisconnects()
Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
+#ifdef QT_BUILD_INTERNAL
+/*
+ Since QObjectPrivate stores the declarativeData pointer in a union with the pointer
+ to the currently destroyed child, calls to the QtDeclarative handlers need to be
+ correctly guarded. QTBUG-105286
+*/
+namespace QtDeclarative {
+static QAbstractDeclarativeData *theData;
+
+static void destroyed(QAbstractDeclarativeData *data, QObject *)
+{
+ QCOMPARE(data, theData);
+}
+static void signalEmitted(QAbstractDeclarativeData *data, QObject *, int, void **)
+{
+ QCOMPARE(data, theData);
+}
+// we can't use QCOMPARE in the next two functions, as they don't return void
+static int receivers(QAbstractDeclarativeData *data, const QObject *, int)
+{
+ QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__);
+ return 0;
+}
+static bool isSignalConnected(QAbstractDeclarativeData *data, const QObject *, int)
+{
+ QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__);
+ return true;
+}
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+ ~Object()
+ {
+ if (Object *p = static_cast<Object *>(parent()))
+ p->emitSignal();
+ }
+
+ void emitSignal()
+ {
+ emit theSignal();
+ }
+
+signals:
+ void theSignal();
+};
+
+}
+#endif
+
+void tst_QObject::declarativeData()
+{
+#ifdef QT_BUILD_INTERNAL
+ QAbstractDeclarativeData::destroyed = QtDeclarative::destroyed;
+ QAbstractDeclarativeData::signalEmitted = QtDeclarative::signalEmitted;
+ QAbstractDeclarativeData::receivers = QtDeclarative::receivers;
+ QAbstractDeclarativeData::isSignalConnected = QtDeclarative::isSignalConnected;
+
+ QtDeclarative::Object p;
+ QObjectPrivate *priv = QObjectPrivate::get(&p);
+ priv->declarativeData = QtDeclarative::theData = new QAbstractDeclarativeData;
+
+ connect(&p, &QtDeclarative::Object::theSignal, &p, []{
+ });
+
+ QtDeclarative::Object *child = new QtDeclarative::Object;
+ child->setParent(&p);
+#endif
+}
+
QTEST_MAIN(tst_QObject)
#include "tst_qobject.moc"