summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
authorPeter Seiderer <ps.report@gmx.net>2013-06-17 22:44:30 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-07-29 22:28:58 +0200
commit6c21f42657b494e24112c90d8b9fff719f1f8791 (patch)
treefeecc49a9431d7f97f7c11102b9468300ee03fba /src/dbus
parent72ecf5a7ecb688a7e19cbc2f70e358a94d02edf7 (diff)
Change QDBusPendingCallPrivate to full reference counting for deletion.
Fixes race between QDBusConnectionPrivate::processFinishedCall() releasing the mutex before emitting signals (using various members of QDBusPendingCallPrivate) and deletion of the QDBusPendingCallPrivate object through QDBusPendingCall::d's destructor (a member of type QExplicitlySharedDataPointer<QDBusPendingCallPrivate>) leeds to segmentation fault with CrashTest example on slow/single core arm cpu). Task-number: QTBUG-27809 Change-Id: I3590d74d1cfa5816ede764b50b83a7008ec780ff Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/qdbusconnection.cpp3
-rw-r--r--src/dbus/qdbusconnection_p.h5
-rw-r--r--src/dbus/qdbusintegrator.cpp87
-rw-r--r--src/dbus/qdbuspendingcall.cpp6
4 files changed, 58 insertions, 43 deletions
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index 74a3a752a5..a29ba4cb0f 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -54,6 +54,7 @@
#include "qdbusinterface_p.h"
#include "qdbusutil_p.h"
#include "qdbusconnectionmanager_p.h"
+#include "qdbuspendingcall_p.h"
#include "qdbusthreaddebug_p.h"
@@ -611,7 +612,7 @@ QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int tim
return QDBusPendingCall(0); // null pointer -> disconnected
}
- QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, timeout);
+ QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, 0, 0, 0, timeout);
return QDBusPendingCall(priv);
}
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 73c8dcf411..c702de141a 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -199,9 +199,8 @@ public:
int send(const QDBusMessage &message);
QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1);
QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
- QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, int timeout = -1);
- int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
- const char *returnMethod, const char *errorMethod, int timeout = -1);
+ QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, const char *errorMethod,int timeout = -1);
bool connectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 4b9bfc3fc8..3f25f02bee 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1901,6 +1901,9 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
if (msg.type() == QDBusMessage::ErrorMessage)
emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
+
+ if (!call->ref.deref())
+ delete call;
}
int QDBusConnectionPrivate::send(const QDBusMessage& message)
@@ -1983,7 +1986,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
return amsg;
} else { // use the event loop
- QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
+ QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, 0, 0, 0, timeout);
Q_ASSERT(pcall);
if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
@@ -1999,6 +2002,10 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
QDBusMessage reply = pcall->replyMessage;
lastError = QDBusError(reply); // set or clear error
+ bool r = pcall->ref.deref();
+ Q_ASSERT(!r);
+ Q_UNUSED(r);
+
delete pcall;
return reply;
}
@@ -2038,19 +2045,55 @@ QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &mess
}
QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
- int timeout)
+ QObject *receiver, const char *returnMethod,
+ const char *errorMethod, int timeout)
{
if (isServiceRegisteredByThread(message.service())) {
// special case for local calls
QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
pcall->replyMessage = sendWithReplyLocal(message);
+ if (receiver && returnMethod)
+ pcall->setReplyCallback(receiver, returnMethod);
+
+ if (errorMethod) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+ Qt::QueuedConnection);
+ pcall->watcherHelper->moveToThread(thread());
+ }
+ if ((receiver && returnMethod) || errorMethod) {
+ // no one waiting, will delete pcall in processFinishedCall()
+ pcall->ref.store(1);
+ } else {
+ // set double ref to prevent race between processFinishedCall() and ref counting
+ // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate>
+ pcall->ref.store(2);
+ }
+ processFinishedCall(pcall);
return pcall;
}
checkThread();
QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
- pcall->ref.store(0);
+ if (receiver && returnMethod)
+ pcall->setReplyCallback(receiver, returnMethod);
+
+ if (errorMethod) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+ Qt::QueuedConnection);
+ pcall->watcherHelper->moveToThread(thread());
+ }
+
+ if ((receiver && returnMethod) || errorMethod) {
+ // no one waiting, will delete pcall in processFinishedCall()
+ pcall->ref.store(1);
+ } else {
+ // set double ref to prevent race between processFinishedCall() and ref counting
+ // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate>
+ pcall->ref.store(2);
+ }
QDBusError error;
DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
@@ -2061,6 +2104,7 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
qPrintable(error.message()));
pcall->replyMessage = QDBusMessage::createError(error);
lastError = error;
+ processFinishedCall(pcall);
return pcall;
}
@@ -2086,45 +2130,10 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
q_dbus_message_unref(msg);
pcall->replyMessage = QDBusMessage::createError(error);
+ processFinishedCall(pcall);
return pcall;
}
-int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
- const char *returnMethod, const char *errorMethod,
- int timeout)
-{
- QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
- Q_ASSERT(pcall);
-
- // has it already finished with success (dispatched locally)?
- if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
- pcall->setReplyCallback(receiver, returnMethod);
- processFinishedCall(pcall);
- delete pcall;
- return 1;
- }
-
- // either it hasn't finished or it has finished with error
- if (errorMethod) {
- pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
- connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
- Qt::QueuedConnection);
- pcall->watcherHelper->moveToThread(thread());
- }
-
- // has it already finished and is an error reply message?
- if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
- processFinishedCall(pcall);
- delete pcall;
- return 1;
- }
-
- pcall->ref.ref();
- pcall->setReplyCallback(receiver, returnMethod);
-
- return 1;
-}
-
bool QDBusConnectionPrivate::connectSignal(const QString &service,
const QString &path, const QString &interface, const QString &name,
const QStringList &argumentMatch, const QString &signature,
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
index 0b4ff3a397..49f9fc0cd8 100644
--- a/src/dbus/qdbuspendingcall.cpp
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -256,6 +256,11 @@ QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
: d(dd)
{
+ if (dd) {
+ bool r = dd->ref.deref();
+ Q_ASSERT(r);
+ Q_UNUSED(r);
+ }
}
/*!
@@ -469,6 +474,7 @@ QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
msg.type() == QDBusMessage::ReplyMessage) {
d = new QDBusPendingCallPrivate(QDBusMessage(), 0);
d->replyMessage = msg;
+ d->ref.store(1);
}
return QDBusPendingCall(d);