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 commit 9d8e78a2f2)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 5d53ea9844)
This commit is contained in:
Ulf Hermann 2024-01-17 09:01:20 +01:00 committed by Qt Cherry-pick Bot
parent cddf2b0b4c
commit c24716c7fe
3 changed files with 57 additions and 1 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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);
}
}