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>
This commit is contained in:
parent
82a2d28d84
commit
7c029e83a3
@ -1876,7 +1876,7 @@ void QObjectPrivate::setParent_helper(QObject *o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
|
if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged)
|
||||||
QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
|
QAbstractDeclarativeData::parentChanged(declarativeData, q, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +152,7 @@ private slots:
|
|||||||
void connectBase();
|
void connectBase();
|
||||||
void qmlConnect();
|
void qmlConnect();
|
||||||
void exceptions();
|
void exceptions();
|
||||||
|
void noDeclarativeParentChangedOnDestruction();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QObjectCreatedOnShutdown
|
struct QObjectCreatedOnShutdown
|
||||||
@ -6233,6 +6234,43 @@ void tst_QObject::exceptions()
|
|||||||
#endif
|
#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
|
// Test for QtPrivate::HasQ_OBJECT_Macro
|
||||||
Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
Q_STATIC_ASSERT(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
||||||
Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
Q_STATIC_ASSERT(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
||||||
|
Loading…
Reference in New Issue
Block a user