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

QLocale::system() is not thread-safe and thus neither is QTime::toString(), QDate::toString(),...

    XMLWordPrintable

Details

    • 188eea0eb47c499f70a60f573948d529089d93b1 (qt/qtbase/5.12)

    Description

      The problem reproduces trivially with the following example. The problem is not reproducible with Qt 5.11.3. The platform I have used is Fedora 29 x86_64 Linux, but I suspect it is the same across platforms.

      #include <QCoreApplication>
      #include <QElapsedTimer>
      #include <QTime>
      #include <QtConcurrentRun>
      
      int main(int argc, char **argv)
      {
          QCoreApplication app(argc, argv);
      
          for (int i = 0; i < 4; ++i) {
              QtConcurrent::run([] {
                 QElapsedTimer tt;
                 tt.start();
                 while (tt.elapsed() < 20000) {
                     QTime(10, 20, 30, 40).toString("hhmmss");
                 }
              });
          }
      }
      

      I compile the example like this:

      g++ -std=c++17 -Wall -Wextra -g -fPIC $(pkg-config Qt5Core Qt5Concurrent --cflags --libs)  -o example example.cc
      

      Here is the backtrace for the crashing thread:

      (gdb) bt
      #0  0x00007ffff7bb253c in QLocaleData::longLongToString (this=0x0, l=10, precision=-1, base=10, width=2, flags=2) at ../../include/QtCore/../../src/corelib/tools/qchar.h:82
      #1  0x00007ffff7bb2973 in QLocalePrivate::dateTimeToString (this=0x7fffe0001050, format=..., datetime=..., dateOnly=..., timeOnly=..., q=0x7fffe7308b58) at tools/qlocale.cpp:2947
      #2  0x00007ffff7bb371f in QLocale::toString (this=this@entry=0x7fffe7308b58, time=..., format=...) at ../../include/QtCore/../../src/corelib/tools/qdatetime.h:139
      #3  0x00007ffff7b9bd99 in QTime::toString (this=0x7fffe7308bd4, format=...) at tools/qdatetime.cpp:1697
      #4  0x00007ffff7b9bdd7 in QTime::toString (this=<optimized out>, format=...) at ../../include/QtCore/../../src/corelib/tools/qstringview.h:178
      #5  0x0000000000402365 in <lambda()>::operator()(void) const (__closure=0x41b3ec) at example.cc:15
      #6  0x000000000040254e in QtConcurrent::StoredFunctorCall0<void, main(int, char**)::<lambda()> >::runFunctor(void) (this=0x41b3d0) at /opt/easyviz/qt/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:70
      #7  0x00000000004027d4 in QtConcurrent::RunFunctionTask<void>::run (this=0x41b3d0) at /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrunbase.h:136
      #8  0x00007ffff7b5cda1 in QThreadPoolThread::run (this=0x41b590) at thread/qthreadpool.cpp:99
      #9  0x00007ffff7b59013 in QThreadPrivate::start (arg=0x41b590) at thread/qthread_unix.cpp:361
      #10 0x00007ffff754c58e in start_thread (arg=<optimized out>) at pthread_create.c:486
      #11 0x00007ffff76656a3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
      

      Compiling with -fsanitize thread does show some interesting warnings in the QLocale area that are only present with Qt 5.12.0. Here is an example:

      ==================
      WARNING: ThreadSanitizer: data race (pid=23147)
        Write of size 8 at 0x7b0400001070 by thread T1:
          #0 operator delete(void*) <null> (libtsan.so.0+0x75ef1)
          #1 QSharedDataPointer<QLocalePrivate>::detach_helper() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:262 (libQt5Core.so.5+0x114378)
          #2 QSharedDataPointer<QLocalePrivate>::detach() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:74 (libQt5Core.so.5+0x114378)
          #3 QSharedDataPointer<QLocalePrivate>::data() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:81 (libQt5Core.so.5+0x114378)
          #4 QLocale::system() tools/qlocale.cpp:2358 (libQt5Core.so.5+0x114378)
          #5 runFunctor /opt/easyviz/qt/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:70 (example+0x4026f4)
          #6 QtConcurrent::RunFunctionTask<void>::run() /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrunbase.h:136 (example+0x402bbf)
          #7 QThreadPoolThread::run() thread/qthreadpool.cpp:99 (libQt5Core.so.5+0xbfda0)
      
        Previous write of size 8 at 0x7b0400001070 by thread T2:
          #0 operator new(unsigned long) <null> (libtsan.so.0+0x75bfa)
          #1 QLocalePrivate::create(QLocaleData const*, QFlags<QLocale::NumberOption>) tools/qlocale_p.h:328 (libQt5Core.so.5+0x1142b0)
          #2 QSharedDataPointer<QLocalePrivate>::clone() tools/qlocale_p.h:383 (libQt5Core.so.5+0x1142b0)
          #3 QSharedDataPointer<QLocalePrivate>::detach_helper() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:259 (libQt5Core.so.5+0x1142b0)
          #4 QSharedDataPointer<QLocalePrivate>::detach() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:74 (libQt5Core.so.5+0x1142b0)
          #5 QSharedDataPointer<QLocalePrivate>::data() ../../include/QtCore/../../src/corelib/tools/qshareddata.h:81 (libQt5Core.so.5+0x1142b0)
          #6 QLocale::system() tools/qlocale.cpp:2358 (libQt5Core.so.5+0x1142b0)
          #7 runFunctor /opt/easyviz/qt/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:70 (example+0x4026f4)
          #8 QtConcurrent::RunFunctionTask<void>::run() /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrunbase.h:136 (example+0x402bbf)
          #9 QThreadPoolThread::run() thread/qthreadpool.cpp:99 (libQt5Core.so.5+0xbfda0)
      
        Thread T1 'Thread (pooled)' (tid=23149, running) created by main thread at:
          #0 pthread_create <null> (libtsan.so.0+0x2cfc2)
          #1 QThread::start(QThread::Priority) thread/qthread_unix.cpp:724 (libQt5Core.so.5+0xbba11)
          #2 QtConcurrent::RunFunctionTaskBase<void>::start() /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrunbase.h:78 (example+0x40316d)
          #3 run<main(int, char**)::<lambda()> > /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrun.h:108 (example+0x40254f)
          #4 main /home/ts/src/easyviz/example.cc:11 (example+0x4024b6)
      
        Thread T2 'Thread (pooled)' (tid=23150, running) created by main thread at:
          #0 pthread_create <null> (libtsan.so.0+0x2cfc2)
          #1 QThread::start(QThread::Priority) thread/qthread_unix.cpp:724 (libQt5Core.so.5+0xbba11)
          #2 QtConcurrent::RunFunctionTaskBase<void>::start() /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrunbase.h:78 (example+0x40316d)
          #3 run<main(int, char**)::<lambda()> > /opt/easyviz/qt/include/QtConcurrent/qtconcurrentrun.h:108 (example+0x40254f)
          #4 main /home/ts/src/easyviz/example.cc:11 (example+0x4024b6)
      
      SUMMARY: ThreadSanitizer: data race (/lib64/libtsan.so.0+0x75ef1) in operator delete(void*)
      ==================
      

      Attachments

        Issue Links

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

          Activity

            People

              thiago Thiago Macieira
              ts Thomas Sondergaard
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes