From ed40ffb381e1f874145b70de43961298428c03af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lutz=20Sch=C3=B6nemann?= Date: Mon, 1 Dec 2014 16:12:22 +0100 Subject: Fix crash on signal after deregistration Implemented a remove method in SignalHandler that allows us to remove and disconnect an object from SignalHandler w/o decrementing the connection counter until it hits zero or deleting the object That same functionality was used to remove an object from internal lists when receiving a destroyed signal from an object. In case of deregistering an object we haven't received a destoryed signal but simulated reception of that signal and so that code was not called in that case. Change-Id: Ie20cf628a2de028375f5d29f913682e25ebf8d44 Reviewed-by: Milian Wolff --- src/webchannel/qmetaobjectpublisher.cpp | 1 + src/webchannel/signalhandler_p.h | 25 ++++++++++++++++--------- tests/auto/webchannel/tst_webchannel.cpp | 24 ++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 1 + 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index b3ae23c..b92cf51 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -403,6 +403,7 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object) Q_ASSERT(removed); Q_UNUSED(removed); + signalHandler.remove(object); signalToPropertyMap.remove(object); pendingPropertyUpdates.remove(object); wrappedObjects.remove(object); diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h index 2560cdb..03fbca9 100644 --- a/src/webchannel/signalhandler_p.h +++ b/src/webchannel/signalhandler_p.h @@ -84,6 +84,11 @@ public: */ void clear(); + /** + * Fully remove and disconnect an object from handler + */ + void remove(const QObject *object); + private: /** * Exctract the arguments of a signal call and pass them to the receiver. @@ -252,15 +257,6 @@ int SignalHandler::qt_metacall(QMetaObject::Call call, int methodId, v dispatch(object, methodId, args); - if (methodId == s_destroyedSignalIndex) { - // disconnect on QObject::destroyed - ConnectionHash::iterator it = m_connectionsCounter.find(object); - Q_ASSERT(it != m_connectionsCounter.end()); - foreach (const ConnectionPair &connection, *it) { - QObject::disconnect(connection.first); - } - m_connectionsCounter.erase(it); - } return -1; } return methodId; @@ -280,6 +276,17 @@ void SignalHandler::clear() m_signalArgumentTypes[&QObject::staticMetaObject] = keep; } +template +void SignalHandler::remove(const QObject *object) +{ + Q_ASSERT(m_connectionsCounter.contains(object)); + const SignalConnectionHash &connections = m_connectionsCounter.value(object); + foreach (const ConnectionPair &connection, connections) { + QObject::disconnect(connection.first); + } + m_connectionsCounter.remove(object); +} + QT_END_NAMESPACE #endif // SIGNALHANDLER_H diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 4827ea7..3304293 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -83,6 +83,30 @@ void TestWebChannel::testRegisterObjects() channel.registerObjects(objects); } +void TestWebChannel::testDeregisterObjects() +{ + QWebChannel channel; + TestObject testObject; + testObject.setObjectName("myTestObject"); + + + channel.registerObject(testObject.objectName(), &testObject); + + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClients(); + + QJsonObject connectMessage = + QJsonDocument::fromJson(("{\"type\": 7," + "\"object\": \"myTestObject\"," + "\"signal\": " + QString::number(testObject.metaObject()->indexOfSignal("sig1()")) + + "}").toLatin1()).object(); + channel.d_func()->publisher->handleMessage(connectMessage, m_dummyTransport); + + emit testObject.sig1(); + channel.deregisterObject(&testObject); + emit testObject.sig1(); +} + void TestWebChannel::testInfoForObject() { TestObject obj; diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index ad8c6a4..6564944 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -214,6 +214,7 @@ public: private slots: void testRegisterObjects(); + void testDeregisterObjects(); void testInfoForObject(); void testInvokeMethodConversion(); void testDisconnect(); -- cgit v1.2.1