From 7c029e83a3e5058f7b82efd0235e766952357ffd Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 28 Nov 2013 11:00:15 +0100 Subject: 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 --- tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'tests/auto') 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 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::Value); Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro::Value); -- cgit v1.2.3