qt5-qtbase/QTBUG-51676-Fix-QtDBus-dead...

82 lines
3.8 KiB
Diff

From 42e14c187f7b2eedb5be7b7a49efb4031f12a02e Mon Sep 17 00:00:00 2001
From: Thiago Macieira <thiago.macieira@intel.com>
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