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
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
parent
64e3bd481e
commit
72ecf5a7ec
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue