From b708a2d9a5d96c826752526d973fe0e752035455 Mon Sep 17 00:00:00 2001
From: Peter Seiderer <ps.report@gmx.net>
Date: Mon, 17 Jun 2013 20:56:08 +0200
Subject: [PATCH 2/3] Remove QDBusPendingCallPrivate::autoDelete logic.

First step to fix race condition about deleting QDBusPendingCallPrivate.

In a multithreaded application on a slow/single core cpu the following
race (and segmentation fault) can occur:

First thread A is running:
A:  QDBusPendingReply<> reply = pi->asyncCallWithArgumentList(method, argumentList);

Then when the dbus answer arrives thread B will call:

B:  QDBusConnectionPrivate::processFinishedCall()
B:      ...
B:      locker.unlock()

and runs until here, go on with thread A:

A:  reply.waitForFinished();
A:    QDBusPendingCallPrivate::waitForFinished()
A:    {
A:        QMutexLocker locker(&mutex);
A:        if (replyMessage.type() != QDBusMessage::InvalidMessage)
A:            return;

which returns immediately (mutex acquired, replyMessage alread set), now
reply goes out of scope (destructor called) and QDBusPendingCall::d's
destructor of type QExplicitlySharedDataPointer<QDBusPendingCallPrivate>
deletes the reference counted object QDBusPendingCallPrivate.

Now thread B continues, still in processFinishedCall()

B:      if (call->watcherHelper)
B:          call->watcherHelper->emitSignals(msg, call->sentMessage);
B:
B:      if (msg.type() == QDBusMessage::ErrorMessage)
B:          emit connection->callWithCallbackFailed(QDBusError(msg),
B:              call->sentMessage);

accessing alread deleted object QDBusPendingCallPrivate via call->...

Fixed QDBusPendingCallPrivate deletion by proper reference counting
will be done in the next commit.

Task-number: QTBUG-27809
Change-Id: I15b3f0242471b62eaafadc763fb6a33339ff2fe1
---
 src/dbus/qdbusintegrator.cpp  | 14 --------------
 src/dbus/qdbuspendingcall_p.h |  3 +--
 2 files changed, 1 insertion(+), 16 deletions(-)

diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 0ea428b..5c901fa 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1828,7 +1828,6 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
 void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall)
 {
     Q_ASSERT(pcall->pending);
-    Q_ASSERT(!pcall->autoDelete);
     //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function
 
     if (pcall->waitingForFinished) {
@@ -1854,13 +1853,6 @@ void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall)
     }
 }
 
-// this function is called only in a Q_ASSERT
-static inline Q_DECL_UNUSED bool waitingForFinishedIsSet(QDBusPendingCallPrivate *call)
-{
-    const QMutexLocker locker(&call->mutex);
-    return call->waitingForFinished;
-}
-
 void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
 {
     QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
@@ -1909,11 +1901,6 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
 
     if (msg.type() == QDBusMessage::ErrorMessage)
         emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
-
-    if (call->autoDelete) {
-        Q_ASSERT(!waitingForFinishedIsSet(call)); // can't wait on a call with autoDelete!
-        delete call;
-    }
 }
 
 int QDBusConnectionPrivate::send(const QDBusMessage& message)
@@ -2132,7 +2119,6 @@ int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObj
         return 1;
     }
 
-    pcall->autoDelete = true;
     pcall->ref.ref();
     pcall->setReplyCallback(receiver, returnMethod);
 
diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h
index 36d0b90..d0b28b3 100644
--- a/src/dbus/qdbuspendingcall_p.h
+++ b/src/dbus/qdbuspendingcall_p.h
@@ -85,7 +85,6 @@ public:
     QVector<int> metaTypes;
     int methodIdx;
 
-    bool autoDelete;
     // }
 
     mutable QMutex mutex;
@@ -102,7 +101,7 @@ public:
     // }
 
     QDBusPendingCallPrivate(const QDBusMessage &sent, QDBusConnectionPrivate *connection)
-        : sentMessage(sent), connection(connection), autoDelete(false), watcherHelper(0), pending(0), waitingForFinished(false)
+        : sentMessage(sent), connection(connection), watcherHelper(0), pending(0), waitingForFinished(false)
     { }
     ~QDBusPendingCallPrivate();
     bool setReplyCallback(QObject *target, const char *member);
-- 
1.8.1.4

