QtQml: Do not call signal handlers on half-deleted objects
Fixes: QTBUG-121022 Change-Id: Icdefd6bef4906700d88eca47c09d0abe54f1eec9 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commit9d8e78a2f2
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit5d53ea9844
)
This commit is contained in:
parent
cddf2b0b4c
commit
c24716c7fe
|
@ -1085,13 +1085,15 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
|
|||
|
||||
static void impl(int which, QSlotObjectBase *this_, QObject *receiver, void **metaArgs, bool *ret)
|
||||
{
|
||||
Q_UNUSED(receiver);
|
||||
switch (which) {
|
||||
case Destroy: {
|
||||
delete static_cast<QObjectSlotDispatcher*>(this_);
|
||||
}
|
||||
break;
|
||||
case Call: {
|
||||
if (QQmlData::wasDeleted(receiver))
|
||||
break;
|
||||
|
||||
QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
|
||||
ExecutionEngine *v4 = This->function.engine();
|
||||
// Might be that we're still connected to a signal that's emitted long
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import Qt.test
|
||||
import QtQml
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
property int a: 0
|
||||
property int b: 0
|
||||
|
||||
signal someSignal
|
||||
|
||||
function destroyObj() {
|
||||
obj.destroy()
|
||||
}
|
||||
|
||||
function test() {
|
||||
++a
|
||||
}
|
||||
|
||||
component DestructionReceiver: QtObject {
|
||||
// Has its own context and therefore can receive Component.onDestruction
|
||||
}
|
||||
|
||||
property QtObject obj: QtObject {
|
||||
property QtObject inner: DestructionReceiver {
|
||||
Component.onDestruction: {
|
||||
// The outer obj is already queued for deletion.
|
||||
// We don't want to see this signal delivered.
|
||||
root.someSignal();
|
||||
++root.b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: someSignal.connect(obj, test)
|
||||
}
|
|
@ -3914,7 +3914,25 @@ void tst_qqmlecmascript::scriptConnect()
|
|||
engine.clearSingletons();
|
||||
QMetaObject::invokeMethod(obj.data(), "mySignal", Qt::DirectConnection);
|
||||
QCOMPARE(obj.data()->property("a").toInt(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
QQmlComponent component(&engine, testFileUrl("scriptConnect.deletion.qml"));
|
||||
|
||||
QScopedPointer<QObject> obj(component.create());
|
||||
QVERIFY2(obj, qPrintable(component.errorString()));
|
||||
QVERIFY(!obj.isNull());
|
||||
|
||||
QCOMPARE(obj->property("a"), 0);
|
||||
|
||||
QMetaObject::invokeMethod(obj.data(), "someSignal");
|
||||
QCOMPARE(obj->property("a"), 1);
|
||||
|
||||
QCOMPARE(obj->property("b"), 0);
|
||||
QMetaObject::invokeMethod(obj.data(), "destroyObj", Qt::DirectConnection);
|
||||
|
||||
QTRY_COMPARE(obj->property("b"), 1);
|
||||
QCOMPARE(obj->property("a"), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue