Details
-
Bug
-
Resolution: Fixed
-
P1: Critical
-
6.3, 6.4, 6.5, 6.6
-
None
-
-
3
-
f762e9b64 (dev), 0e8bd451a (6.7), 68d04b599 (6.6), 3d5967dec (tqtc/lts-6.5), 682b99936 (tqtc/lts-6.2)
-
Foundations Sprint 97
Description
The short version: the internal mainThreadCoUnInit() function in qtconnectivity/src/bluetooth
/qbluetoothutils_winrt.cpp fails to check if QCoreApplication::instance() returns nullptr, before attempting to dereference the result, causing a segmentation fault if Bluetooth objects are destroyed as part of the QCoreApplication's QObject-based auto-deletion of children.
Consider, for example, the following example (there may be better ways to do this, it just shows one trivial way to cause a segfault within Qt libraries; the example code is also attached in case it doesn't render well here):
#include <QBluetoothDeviceDiscoveryAgent>
#include <QCoreApplication>
#include <QTimer>
int main(int argc, char *argv[])
{{{}}
QCoreApplication app(argc, argv);
QBluetoothDeviceDiscoveryAgent * discoveryAgent = new QBluetoothDeviceDiscoveryAgent(&app);
QObject::connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
[](const QBluetoothDeviceInfo &info) {
qDebug() << "discovered" << info.address() << info.deviceUuid() << info.name();
}); QObject::connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::errorOccurred,
[](const QBluetoothDeviceDiscoveryAgent::Error &error) {
qDebug() << "discovery error" << error;
QCoreApplication::exit(EXIT_FAILURE);
}); QObject::connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
[]() {
qDebug() << "discovery finished";
QCoreApplication::exit(EXIT_SUCCESS);
}); QTimer::singleShot(0, QCoreApplication::instance(), [discoveryAgent](){
discoveryAgent->start();
}); const int result = QCoreApplication::exec();
//delete discoveryAgent;
return result;
}
Here, because the discoveryAgent is parented by the core application (in real-world examples it wouldn't be a direct child, but rather descend several levels). So when the application is being destroyed, QCoreApplication clears it internal data, before its super (QObject) deletes the discoveryAgent. So when the discoveryAgent is being destroyed, it results in mainThreadCoUnInit() being called internally, which tries to access QCoreApplication::instance() which is now nullptr.
Presumably, the fix is to update mainThreadCoUnInit() to replace the line:
if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
with something like:
if (QCoreApplication::instance() != nullptr && QThread::currentThread() != QCoreApplication::instance()->thread()) {
In the meantime, I'll need to ensure I manually delete my discovery agent before exiting the application. For example, if I uncomment the "delete discoveryAgent" line above, the application will exit cleanly.
Let me know if I can help any more.
Cheers.
PS Might be helpful to note, the internal Qt code in question was added as part of https://bugreports.qt.io/browse/QTBUG-101953