summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-11-28 11:00:15 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-29 09:54:47 +0100
commit7c029e83a3e5058f7b82efd0235e766952357ffd (patch)
treec299996ff3b85c1e173fdcf68e378b9d3b71df3e /tests
parent82a2d28d841c7f59fa76fae6a67e1712a5fb4740 (diff)
Fix invalid memory read when shutting down QML applications
As the last line in the QObject destructor, we call setParentHelper(0) to remove ourselves from the parent. In the process of that we also initiate the QML parentChanged callback. The first thing that parentChanged callback used to do (but now does it too late, after 26350b5ceafa0ade1328037f6234a7d288eb8f48 in qtdeclarative) is to check if the object was deleted and then return. We could re-introduce the check there, but I think it's cleaner to not bother calling the callback on a dead object in the first place. Change-Id: Ia4d43b65a9b3744a451b4c312a2d6f9c0e3b67dc Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp38
1 files changed, 38 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index ece88d47e3..f1e04511cd 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -152,6 +152,7 @@ private slots:
void connectBase();
void qmlConnect();
void exceptions();
+ void noDeclarativeParentChangedOnDestruction();
};
struct QObjectCreatedOnShutdown
@@ -6233,6 +6234,43 @@ void tst_QObject::exceptions()
#endif
}
+#ifdef QT_BUILD_INTERNAL
+static bool parentChangeCalled = false;
+
+static void testParentChanged(QAbstractDeclarativeData *, QObject *, QObject *)
+{
+ parentChangeCalled = true;
+}
+#endif
+
+void tst_QObject::noDeclarativeParentChangedOnDestruction()
+{
+#ifdef QT_BUILD_INTERNAL
+ typedef void (*ParentChangedCallback)(QAbstractDeclarativeData *, QObject *, QObject *);
+ QScopedValueRollback<ParentChangedCallback> rollback(QAbstractDeclarativeData::parentChanged);
+ QAbstractDeclarativeData::parentChanged = testParentChanged;
+
+ QObject *parent = new QObject;
+ QObject *child = new QObject;
+
+ QAbstractDeclarativeData dummy;
+ QObjectPrivate::get(child)->declarativeData = &dummy;
+
+ parentChangeCalled = false;
+ child->setParent(parent);
+
+ QVERIFY(parentChangeCalled);
+ parentChangeCalled = false;
+
+ delete child;
+ QVERIFY(!parentChangeCalled);
+
+ delete parent;
+#else
+ QSKIP("Needs QT_BUILD_INTERNAL");
+#endif
+}
+
// Test for QtPrivate::HasQ_OBJECT_Macro
Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);