Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-52337

Data race in QDBusConnection::connectToBus

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.6.1
    • 5.6.0
    • Core: Threads
    • 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.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            thiago Thiago Macieira
            lessandrovf Lessandro Mariano
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes