Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.6.0
-
None
-
Ubuntu 14.04 x86_64, Qt 5.6.0 built from the source zip.
-
112e53fdc4e46a5e94cb2d575d132e2015694407
Description
There's a small data race in QDBusConnection::connectToDbus. I've attached a report from the tool that found the error (Pareon Verify) which contains the stack traces for the racy accesses.
The error boils down to a signal being sent to a thread that is still starting. In a high-level view, we have this function in qdbusconnection.cpp:514:
QDBusConnection QDBusConnection::connectToBus(...)
{
...
return QDBusConnection(_q_manager()->connectToBus(address, name));
}
_q_manager() creates a QDBusConnectionManager object, which inherits from QThread. The manager object then moves to itself, and starts itself (qdbusconnection.cpp:154):
QDBusConnectionManager::QDBusConnectionManager() { ... moveToThread(this); // ugly, don't do this in other projects ... start(); }
QThread::start returns before the thread has finished starting, therefore it is unsafe to read the new thread ID without additional synchronization.
However, that is exactly what happens when QDBusConnectionManager::connectToBus sends a signal to the manager object – QMetaObject::activate reads the threadId of the receiver's thread in qobject.cpp:3676:
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) ... const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId; ... }
And that races with the write to threadId in the thread start routine in qthread_unix.cpp:311:
void *QThreadPrivate::start(void *arg) { ... { QMutexLocker locker(&thr->d_func()->mutex); ... data->threadId = (Qt::HANDLE)pthread_self(); ... } ... }
QMetaObject::activate does not hold the thread mutex when reading the threadId.