Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
5.15.10, 6.4.2, 6.4.3
-
None
-
Statically linked Qt, with OpenSSL 1.1.1w.
Description
This issue was discovered in qBittorrent (it is affecting all 4.5.x and the 4.6.0 versions qBittorrent, both qt5 and qt6 builds from 4.5.x, I've tagged a few qt versions in the affected field, but the bug is probably more widespread).
The relevant piece of code (freeDiskSpaceChecker just emits a signal with the free disk space):
auto *freeDiskSpaceChecker = new FreeDiskSpaceChecker; connect(freeDiskSpaceChecker, &FreeDiskSpaceChecker::checked, this, [this, freeDiskSpaceChecker](const qint64 freeSpaceSize) { m_freeDiskSpace = freeSpaceSize; m_isFreeDiskSpaceCheckerRunning = false; m_freeDiskSpaceElapsedTimer.restart(); freeDiskSpaceChecker->deleteLater(); });
This randomly (and somewhat rarely) leads to crashes due to nullptr dereference.
What seems to be happening (based on debug printing added to parts of the qt code) is that doActivate() with freeDiskSpaceChecker as the sender and the QObject::~QObject destructor for the same freeDiskSpaceChecker (triggered by deleteLater() in the slot) are running in parallel threads, leading to the following sequence of events:
- check for currentConnectionId happens on thread 1
- currentConnectionId becomes 0 on thread 2
- connections gets set to null on thread 2
- cleanOrphanedConnections gets called on the (now) nullptr connections on thread 1
The actual debug logging that was added / the output is detailed in https://github.com/qbittorrent/qBittorrent/issues/19732#issuecomment-1788274402 (sadly adding debug prints to the QObject::~QObject destructor breaks the timing of the issue, the only thing that worked was to add a destructor to the FreeDiskSpaceChecker class and log from there, but we can clearly see that the deleteLater() call and the destructor runs in a separate thread, after the currentConnectionId == 0 check is done, but before the cleanOrphanedConnections() call.
The issue might be the same as https://bugreports.qt.io/browse/QTBUG-98144
I haven't tried to create a simplified example of the crash (partly because my experience with qt is close to 0 - I'm only a user of qBittorrent who was affected by this crash and attempted to figure out why they are happening).
Considering that it is heavily timing related, it would be pretty hard to create a test case that always reproduces (the linked reproduction sometimes took minutes with the binary being bombarded with 10 webAPI calls parallel - in the real world I had 3-4 crashes a week with 60 qBittorrent instances running with moderate webAPI traffic).
Attachments
Issue Links
- relates to
-
QTBUG-127880 Race condition in QFuture implementation
- Closed