Details
-
Bug
-
Resolution: Incomplete
-
P2: Important
-
None
-
5.15.17, 6.5.0
-
None
Description
I noticed a TSAN warning on some code using QtDBus (elided for brevity):
WARNING: ThreadSanitizer: data race (pid=3404390) Write of size 8 at 0x7b1c000009a0 by thread T1: #0 operator delete(void*, unsigned long) <null> (libtsan.so.2+0x8782d) #1 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) <null> (libQt5Core.so.5+0x2a085d) Previous write of size 8 at 0x7b1c000009a0 by main thread: #0 operator new(unsigned long) <null> (libtsan.so.2+0x87f13) #1 void doActivate<false>(QObject*, int, void**) <null> (libQt5Core.so.5+0x2d0f36) <snip> #5 main <null> (xochitl+0x405a2b) Thread T1 'QDBusConnection' (tid=3404392, running) created by main thread at: #0 pthread_create <null> (libtsan.so.2+0x5f0e6) #1 QThread::start(QThread::Priority) <null> (libQt5Core.so.5+0xe7fad) <snip> #5 main <null> (xochitl+0x405a2b)
The way I read this, the main thread was trying to post an event (queued emission, or method invoke?), at the same time as QDBusConnection's thread stomped on the QPostEventList by calling QCoreApplication::sendPostedEvents.
Looking at QtDBus, the only place I see this used is in QDBusPendingCallWatcher. Indeed, there are two calls to it in QDBusPendingCallWatcher::waitForFinished, and one of them looks to match up with what I see happening here, on our main thread:
- We have some code in a generated QDBusAbstractInterface that makes an asyncCallWithArgumentList, and returns a QDBusPendingReply
- Internally, this moves the watcherHelper to the connection thread (inside QDBusConnectionPrivate::sendWithReplyAsync)
- We then call QDBusPendingReply::waitForFinished on this reply
- The call completes
- QDBusPendingReply then calls sendPostedEvents on the watcherHelper that now lives on the QDBusConnection thread (bad!)
- Then on the QDBusPendingCallWatcher itself (ok)
This should be fixed, since I guess it will potentially cause posted events to go missing, or worse...