From 42e14c187f7b2eedb5be7b7a49efb4031f12a02e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 15 Mar 2016 11:00:20 -0700 Subject: [PATCH] Fix QtDBus deadlock inside kded/kiod Whenever a message spy was installed, we failed to actually process looped-back messages by queueing them for processing by the spy. That had as a consequence that the caller got an error reply and the message, later, we attempted to deliver the message. Since that message still was isLocal==true, bad things happened inside the manager thread. The correct solution is not to queue the message for the filter. We could have filtered the message directly, but instead this commit opts not to filter looped-back messages. That implies kded/kiod must not attempt to load its modules by way of a looped-back message. Task-number: QTBUG-51676 Change-Id: I1dc112894cde7121e8ce302ae51b438ade1ff612 --- src/dbus/qdbusintegrator.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index cd44861..6052766 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -509,7 +509,12 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) { if (!ref.load()) return false; - if (!dispatchEnabled && !QDBusMessagePrivate::isLocal(amsg)) { + + // local message are always delivered, regardless of filtering + // or whether the dispatcher is enabled + bool isLocal = QDBusMessagePrivate::isLocal(amsg); + + if (!dispatchEnabled && !isLocal) { // queue messages only, we'll handle them later qDBusDebug() << this << "delivery is suspended"; pendingMessages << amsg; @@ -524,7 +529,7 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg) return false; case QDBusMessage::MethodCallMessage: // run it through the spy filters (if any) before the regular processing - if (Q_UNLIKELY(qDBusSpyHookList.exists()) && qApp) { + if (Q_UNLIKELY(qDBusSpyHookList.exists()) && !isLocal && qApp) { const QDBusSpyHookList &list = *qDBusSpyHookList; qDBusDebug() << this << "invoking message spies"; QCoreApplication::postEvent(qApp, new QDBusSpyCallEvent(this, QDBusConnection(this), @@ -1451,9 +1456,9 @@ void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg) // that means the dispatchLock mutex is locked // must not call out to user code in that case // - // however, if the message is internal, handleMessage was called - // directly and no lock is in place. We can therefore call out to - // user code, if necessary + // however, if the message is internal, handleMessage was called directly + // (user's thread) and no lock is in place. We can therefore call out to + // user code, if necessary. ObjectTreeNode result; int usedLength; QThread *objThread = 0; @@ -1492,12 +1497,14 @@ void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg) usedLength, msg)); return; } else if (objThread != QThread::currentThread()) { - // synchronize with other thread + // looped-back message, targeting another thread: + // synchronize with it postEventToThread(HandleObjectCallPostEventAction, result.obj, new QDBusActivateObjectEvent(QDBusConnection(this), this, result, usedLength, msg, &sem)); semWait = true; } else { + // looped-back message, targeting current thread semWait = false; } } // release the lock -- 2.5.0