From 72ecf5a7ecb688a7e19cbc2f70e358a94d02edf7 Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Mon, 17 Jun 2013 20:56:08 +0200 Subject: 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 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 Reviewed-by: Thiago Macieira --- 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 ed019cb662..4b9bfc3fc8 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(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 36d0b9023a..d0b28b3c0e 100644 --- a/src/dbus/qdbuspendingcall_p.h +++ b/src/dbus/qdbuspendingcall_p.h @@ -85,7 +85,6 @@ public: QVector 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); -- cgit v1.2.3