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

Data race in QNetworkAccessManager

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 6.7.2
    • Network
    • None
    • Qt 6.7.2 build with Clang 19 with flags '-debug' and '-sanitize thread'
    • Linux/X11

    Description

      TSAN reports a data race in the following code:

      #include <QCoreApplication>
      #include <QNetworkAccessManager>
      #include <QNetworkReply>
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
      
          QUrl url("https://jsonplaceholder.typicode.com/posts/1"); // Example URL
          QNetworkRequest request(url);
      
          QEventLoop loop;
          QNetworkAccessManager manager;
          QNetworkReply *reply = manager.get(request);
          QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
      
          loop.exec();
          return 0;
      }
      

      Output:

      ==================
      WARNING: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) (pid=21616)
        Write of size 8 at 0x72480000e580 by thread T1:
          #0 QObject::~QObject() /qt5/qtbase/src/corelib/kernel/qobject.cpp:1041:1 (libQt6Core.so.6+0x33df20) 
          #1 QHttpThreadDelegate::~QHttpThreadDelegate() /qt5/qtbase/src/network/access/qhttpthreaddelegate.cpp:181:1 (libQt6Network.so.6+0x261803) 
          #2 QHttpThreadDelegate::~QHttpThreadDelegate() /qt5/qtbase/src/network/access/qhttpthreaddelegate.cpp:170:1 (libQt6Network.so.6+0x261839) 
          #3 qDeleteInEventHandler(QObject*) /qt5/qtbase/src/corelib/kernel/qobject.cpp:5002:5 (libQt6Core.so.6+0x33fd2d) 
          #4 QObject::event(QEvent*) /qt5/qtbase/src/corelib/kernel/qobject.cpp:1437:9 (libQt6Core.so.6+0x33f993) 
          #5 QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1316:26 (libQt6Core.so.6+0x25df96) 
          #6 doNotify(QObject*, QEvent*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1243:47 (libQt6Core.so.6+0x25d7e8) 
          #7 QCoreApplication::notify(QObject*, QEvent*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1226:12 (libQt6Core.so.6+0x25d981) 
          #8 QCoreApplication::notifyInternal2(QObject*, QEvent*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1142:18 (libQt6Core.so.6+0x25d69e) 
          #9 QCoreApplication::sendEvent(QObject*, QEvent*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1583:12 (libQt6Core.so.6+0x25e99e) 
          #10 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) /qt5/qtbase/src/corelib/kernel/qcoreapplication.cpp:1940:9 (libQt6Core.so.6+0x25ffd8) 
          #11 QEventDispatcherUNIX::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) /qt5/qtbase/src/corelib/kernel/qeventdispatcher_unix.cpp:415:5 (libQt6Core.so.6+0x6d0b36) 
          #12 QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) /qt5/qtbase/src/corelib/kernel/qeventloop.cpp:100:55 (libQt6Core.so.6+0x281bc8) 
          #13 QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) /qt5/qtbase/src/corelib/kernel/qeventloop.cpp:182:9 (libQt6Core.so.6+0x281e2b) 
          #14 QThread::exec() /qt5/qtbase/src/corelib/thread/qthread.cpp:586:32 (libQt6Core.so.6+0x4fdbd2) 
          #15 QThread::run() /qt5/qtbase/src/corelib/thread/qthread.cpp:707:12 (libQt6Core.so.6+0x4fe365) 
          #16 QThreadPrivate::start(void*)::$_0::operator()() const /qt5/qtbase/src/corelib/thread/qthread_unix.cpp:326:14 (libQt6Core.so.6+0x6cd9b0) 
          #17 void (anonymous namespace)::terminate_on_exception<QThreadPrivate::start(void*)::$_0>(QThreadPrivate::start(void*)::$_0&&) /qt5/qtbase/src/corelib/thread/qthread_unix.cpp:262:9 (libQt6Core.so.6+0x6cbe55) 
          #18 QThreadPrivate::start(void*) /qt5/qtbase/src/corelib/thread/qthread_unix.cpp:285:5 (libQt6Core.so.6+0x6cbd59) 
      
        Previous read of size 8 at 0x72480000e580 by main thread (mutexes: write M0):
          #0 QObject::~QObject() /qt5/qtbase/src/corelib/kernel/qobject.cpp:1117:73 (libQt6Core.so.6+0x33e4be) 
          #1 QIODevice::~QIODevice() /qt5/qtbase/src/corelib/io/qiodevice.cpp:466:1 (libQt6Core.so.6+0x1cbe15) 
          #2 QNetworkReply::~QNetworkReply() /qt5/qtbase/src/network/access/qnetworkreply.cpp:457:1 (libQt6Network.so.6+0xdd375) 
          #3 QNetworkReplyHttpImpl::~QNetworkReplyHttpImpl() /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:228:1 (libQt6Network.so.6+0x26be94) 
          #4 QNetworkReplyHttpImpl::~QNetworkReplyHttpImpl() /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:225:1 (libQt6Network.so.6+0x26bf19) 
          #5 void qDeleteAll<QList<QNetworkReply*>::const_iterator>(QList<QNetworkReply*>::const_iterator, QList<QNetworkReply*>::const_iterator) /qt5/qtbase/src/corelib/tools/qalgorithms.h:27:9 (libQt6Network.so.6+0xba896) 
          #6 void qDeleteAll<QList<QNetworkReply*>>(QList<QNetworkReply*> const&) /qt5/qtbase/src/corelib/tools/qalgorithms.h:35:5 (libQt6Network.so.6+0xaac93) 
          #7 QNetworkAccessManager::~QNetworkAccessManager() /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:436:5 (libQt6Network.so.6+0xa370d) 
          #8 main /root/src/src/main.cpp:19:1 (Test+0x2242f2)
      
        Location is heap block of size 376 at 0x72480000e580 allocated by main thread:
          #0 operator new(unsigned long) <null> (Test+0x21caa6)
          #1 QNetworkReplyHttpImplPrivate::postRequest(QNetworkRequest const&) /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:808:37 (libQt6Network.so.6+0x270d81) 
          #2 QNetworkReplyHttpImplPrivate::_q_startOperation() /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:1898:5 (libQt6Network.so.6+0x26bdcf) 
          #3 QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager*, QNetworkRequest const&, QNetworkAccessManager::Operation&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:220:12 (libQt6Network.so.6+0x26bbec) 
          #4 QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation, QNetworkRequest const&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:1281:44 (libQt6Network.so.6+0xa601e) 
          #5 QNetworkAccessManager::get(QNetworkRequest const&) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:780:34 (libQt6Network.so.6+0xa43bf) 
          #6 main /root/src/src/main.cpp:14:36 (Test+0x22421c)
      
        Mutex M0 (0x7f5eed7aa6c8) created at:
          #0 __tsan_mutex_pre_lock <null> (Test+0x1ef077)
          #1 QtTsan::mutexPreLock(void*, unsigned int) /qt5/qtbase/src/corelib/thread/qtsan_impl.h:38:5 (libQt6Core.so.6+0x11dcf1) 
          #2 QBasicMutex::lock() /qt5/qtbase/src/corelib/thread/qmutex.h:38:9 (libQt6Core.so.6+0x11dc7b) 
          #3 QOrderedMutexLocker::relock() /qt5/qtbase/src/corelib/thread/qorderedmutexlocker_p.h:69:29 (libQt6Core.so.6+0x35b79f) 
          #4 QOrderedMutexLocker::QOrderedMutexLocker(QBasicMutex*, QBasicMutex*) /qt5/qtbase/src/corelib/thread/qorderedmutexlocker_p.h:40:9 (libQt6Core.so.6+0x354041) 
          #5 QObjectPrivate::connectImpl(QObject const*, int, QObject const*, void**, QtPrivate::QSlotObjectBase*, int, int const*, QMetaObject const*) /qt5/qtbase/src/corelib/kernel/qobject.cpp:5232:25 (libQt6Core.so.6+0x34c1d7) 
          #6 QObject::connectImpl(QObject const*, void**, QObject const*, void**, QtPrivate::QSlotObjectBase*, Qt::ConnectionType, int const*, QMetaObject const*) /qt5/qtbase/src/corelib/kernel/qobject.cpp:5189:12 (libQt6Core.so.6+0x34bfec) 
          #7 QMetaObject::Connection QObjectPrivate::connect<void (QNetworkReply::*)(), void (QNetworkReplyHttpImplPrivate::*)()>(QtPrivate::FunctionPointer<void (QNetworkReply::*)()>::Object const*, void (QNetworkReply::*)(), QtPrivate::FunctionPointer<void (QNetworkReplyHttpImplPrivate::*)()>::Object const*, void (QNetworkReplyHttpImplPrivate::*)(), Qt::ConnectionType) /qt5/qtbase/src/corelib/kernel/qobject_p.h:318:12 (libQt6Network.so.6+0x27ad97) 
          #8 QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager*, QNetworkRequest const&, QNetworkAccessManager::Operation&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:161:5 (libQt6Network.so.6+0x26b827) 
          #9 QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation, QNetworkRequest const&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:1281:44 (libQt6Network.so.6+0xa601e) 
          #10 QNetworkAccessManager::get(QNetworkRequest const&) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:780:34 (libQt6Network.so.6+0xa43bf) 
          #11 main /root/src/src/main.cpp:14:36 (Test+0x22421c)
      
        Thread T1 'QNetworkAccessM' (tid=21618, running) created by main thread at:
          #0 pthread_create <null> (Test+0x198225)
          #1 QThread::start(QThread::Priority) /qt5/qtbase/src/corelib/thread/qthread_unix.cpp:723:16 (libQt6Core.so.6+0x6cc922) 
          #2 QNetworkAccessManagerPrivate::createThread() /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:1694:17 (libQt6Network.so.6+0xa7fdb) 
          #3 QNetworkReplyHttpImplPrivate::postRequest(QNetworkRequest const&) /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:639:34 (libQt6Network.so.6+0x26fa06) 
          #4 QNetworkReplyHttpImplPrivate::_q_startOperation() /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:1898:5 (libQt6Network.so.6+0x26bdcf) 
          #5 QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager*, QNetworkRequest const&, QNetworkAccessManager::Operation&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkreplyhttpimpl.cpp:220:12 (libQt6Network.so.6+0x26bbec) 
          #6 QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation, QNetworkRequest const&, QIODevice*) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:1281:44 (libQt6Network.so.6+0xa601e) 
          #7 QNetworkAccessManager::get(QNetworkRequest const&) /qt5/qtbase/src/network/access/qnetworkaccessmanager.cpp:780:34 (libQt6Network.so.6+0xa43bf) 
          #8 main /root/src/src/main.cpp:14:36 (Test+0x22421c)
      
      SUMMARY: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) /qt5/qtbase/src/corelib/kernel/qobject.cpp:1041:1 in QObject::~QObject()
      ==================
      ThreadSanitizer: reported 1 warnings
      
      

      From what I can understand the following happens: `QHttpThreadDelegate` is destroying in T1 (Networkmanager's thread) and meantime the main thread is calling `qDeleteAll<QList<QNetworkReply*>>` which calls `QObject::metaObject` for the `QHttpThreadDelegate` object. So one thread is calling destructor of the object and another thread is calling a virtual function of it. Technically this is a data race on vtable (this is what TSAN reports).

      Attachments

        Issue Links

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

          Activity

            People

              manordheim Mårten Nordheim
              tyler92 Mike H
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes