diff options
author | Juha Vuolle <juha.vuolle@insta.fi> | 2022-06-20 09:13:58 +0300 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-06-22 06:09:31 +0000 |
commit | ba7f545a8920be04a800694f1138e33080dd8c8c (patch) | |
tree | 888f349e88745d36e3e6dec2f08d3517824c98ee | |
parent | 1d5d325b8c1b2c086f8a1e1bc66779e0af009ec1 (diff) |
Fix Bluez LE advertiser delete crash
Bluez LE advertiser and Bluez LE controller use/share an instance of
HCI manager, and in some circumstances the deletion of the LE controller
leads to a crash. This is because:
1) LE advertiser and HCI manager are parented to the LE controller
2) LE advertiser uses HCI manager in its destructor
=> When LE controller is deleted, its QObject children are deleted.
If the HCI manager happens to be deleted first, the advertiser uses
a by-now deleted HCI manager in its destructor
This commit makes the HCI manager a shared resource so that the exact
destruction order does not matter.
As a drive-by set deleted cmacCalculator pointer to nullptr.
Fixes: QTBUG-104105
Change-Id: I1c5e319af2fc59c4d5bb1fed33b8824eb3c4cb29
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
(cherry picked from commit f1ff9f4d17b82b5e597e28118de62beab705519e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | src/bluetooth/bluez/hcimanager.cpp | 4 | ||||
-rw-r--r-- | src/bluetooth/bluez/hcimanager_p.h | 2 | ||||
-rw-r--r-- | src/bluetooth/qleadvertiser_bluez.cpp | 11 | ||||
-rw-r--r-- | src/bluetooth/qleadvertiser_bluez_p.h | 5 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez.cpp | 15 | ||||
-rw-r--r-- | src/bluetooth/qlowenergycontroller_bluez_p.h | 2 |
6 files changed, 22 insertions, 17 deletions
diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp index 43faec22..8b6b52b4 100644 --- a/src/bluetooth/bluez/hcimanager.cpp +++ b/src/bluetooth/bluez/hcimanager.cpp @@ -57,8 +57,8 @@ QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) -HciManager::HciManager(const QBluetoothAddress& deviceAdapter, QObject *parent) : - QObject(parent), hciSocket(-1), hciDev(-1) +HciManager::HciManager(const QBluetoothAddress& deviceAdapter) : + QObject(nullptr), hciSocket(-1), hciDev(-1) { hciSocket = ::socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI); if (hciSocket < 0) { diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h index d624edc7..69bf7e48 100644 --- a/src/bluetooth/bluez/hcimanager_p.h +++ b/src/bluetooth/bluez/hcimanager_p.h @@ -192,7 +192,7 @@ public: }; Q_ENUM(HciError); - explicit HciManager(const QBluetoothAddress &deviceAdapter, QObject *parent = nullptr); + explicit HciManager(const QBluetoothAddress &deviceAdapter); ~HciManager(); bool isValid() const; diff --git a/src/bluetooth/qleadvertiser_bluez.cpp b/src/bluetooth/qleadvertiser_bluez.cpp index 22d77ee8..e0ef450f 100644 --- a/src/bluetooth/qleadvertiser_bluez.cpp +++ b/src/bluetooth/qleadvertiser_bluez.cpp @@ -82,23 +82,24 @@ static QByteArray byteArrayFromStruct(const T &data) QLeAdvertiserBluez::QLeAdvertiserBluez(const QLowEnergyAdvertisingParameters ¶ms, const QLowEnergyAdvertisingData &advertisingData, const QLowEnergyAdvertisingData &scanResponseData, - HciManager &hciManager, QObject *parent) + std::shared_ptr<HciManager> hciManager, QObject *parent) : QLeAdvertiser(params, advertisingData, scanResponseData, parent), m_hciManager(hciManager) { - connect(&m_hciManager, &HciManager::commandCompleted, this, + Q_ASSERT(m_hciManager); + connect(m_hciManager.get(), &HciManager::commandCompleted, this, &QLeAdvertiserBluez::handleCommandCompleted); } QLeAdvertiserBluez::~QLeAdvertiserBluez() { - disconnect(&m_hciManager, &HciManager::commandCompleted, this, + disconnect(m_hciManager.get(), &HciManager::commandCompleted, this, &QLeAdvertiserBluez::handleCommandCompleted); doStopAdvertising(); } void QLeAdvertiserBluez::doStartAdvertising() { - if (!m_hciManager.monitorEvent(HciManager::HciEvent::EVT_CMD_COMPLETE)) { + if (!m_hciManager->monitorEvent(HciManager::HciEvent::EVT_CMD_COMPLETE)) { handleError(); return; } @@ -130,7 +131,7 @@ void QLeAdvertiserBluez::sendNextCommand() return; } const Command &c = m_pendingCommands.first(); - if (!m_hciManager.sendCommand(QBluezConst::OgfLinkControl, c.ocf, c.data)) { + if (!m_hciManager->sendCommand(QBluezConst::OgfLinkControl, c.ocf, c.data)) { handleError(); return; } diff --git a/src/bluetooth/qleadvertiser_bluez_p.h b/src/bluetooth/qleadvertiser_bluez_p.h index 683bd25f..312889d3 100644 --- a/src/bluetooth/qleadvertiser_bluez_p.h +++ b/src/bluetooth/qleadvertiser_bluez_p.h @@ -104,7 +104,8 @@ class QLeAdvertiserBluez : public QLeAdvertiser public: QLeAdvertiserBluez(const QLowEnergyAdvertisingParameters ¶ms, const QLowEnergyAdvertisingData &advertisingData, - const QLowEnergyAdvertisingData &scanResponseData, HciManager &hciManager, + const QLowEnergyAdvertisingData &scanResponseData, + std::shared_ptr<HciManager> hciManager, QObject *parent = nullptr); ~QLeAdvertiserBluez() override; @@ -133,7 +134,7 @@ private: void handleCommandCompleted(quint16 opCode, quint8 status, const QByteArray &advertisingData); void handleError(); - HciManager &m_hciManager; + std::shared_ptr<HciManager> m_hciManager; struct Command { Command() {} diff --git a/src/bluetooth/qlowenergycontroller_bluez.cpp b/src/bluetooth/qlowenergycontroller_bluez.cpp index 406bdecd..4718f0a8 100644 --- a/src/bluetooth/qlowenergycontroller_bluez.cpp +++ b/src/bluetooth/qlowenergycontroller_bluez.cpp @@ -223,28 +223,30 @@ QLowEnergyControllerPrivateBluez::QLowEnergyControllerPrivateBluez() void QLowEnergyControllerPrivateBluez::init() { - hciManager = new HciManager(localAdapter, this); + // The HCI manager is shared between this class and the advertiser + hciManager = std::make_shared<HciManager>(localAdapter); + if (!hciManager->isValid()){ setError(QLowEnergyController::InvalidBluetoothAdapterError); return; } hciManager->monitorEvent(HciManager::HciEvent::EVT_ENCRYPT_CHANGE); - connect(hciManager, SIGNAL(encryptionChangedEvent(QBluetoothAddress,bool)), + connect(hciManager.get(), SIGNAL(encryptionChangedEvent(QBluetoothAddress,bool)), this, SLOT(encryptionChangedEvent(QBluetoothAddress,bool))); hciManager->monitorEvent(HciManager::HciEvent::EVT_LE_META_EVENT); hciManager->monitorAclPackets(); - connect(hciManager, &HciManager::connectionComplete, [this](quint16 handle) { + connect(hciManager.get(), &HciManager::connectionComplete, [this](quint16 handle) { connectionHandle = handle; qCDebug(QT_BT_BLUEZ) << "received connection complete event, handle:" << handle; }); - connect(hciManager, &HciManager::connectionUpdate, + connect(hciManager.get(), &HciManager::connectionUpdate, [this](quint16 handle, const QLowEnergyConnectionParameters ¶ms) { if (handle == connectionHandle) emit q_ptr->connectionUpdated(params); } ); - connect(hciManager, &HciManager::signatureResolvingKeyReceived, + connect(hciManager.get(), &HciManager::signatureResolvingKeyReceived, [this](quint16 handle, bool remoteKey, const quint128 &csrk) { if (handle != connectionHandle) return; @@ -367,6 +369,7 @@ QLowEnergyControllerPrivateBluez::~QLowEnergyControllerPrivateBluez() { closeServerSocket(); delete cmacCalculator; + cmacCalculator = nullptr; } class ServerSocket @@ -425,7 +428,7 @@ void QLowEnergyControllerPrivateBluez::startAdvertising(const QLowEnergyAdvertis { qCDebug(QT_BT_BLUEZ) << "Starting to advertise"; if (!advertiser) { - advertiser = new QLeAdvertiserBluez(params, advertisingData, scanResponseData, *hciManager, + advertiser = new QLeAdvertiserBluez(params, advertisingData, scanResponseData, hciManager, this); connect(advertiser, &QLeAdvertiser::errorOccurred, this, &QLowEnergyControllerPrivateBluez::handleAdvertisingError); diff --git a/src/bluetooth/qlowenergycontroller_bluez_p.h b/src/bluetooth/qlowenergycontroller_bluez_p.h index 6f373479..d622de7d 100644 --- a/src/bluetooth/qlowenergycontroller_bluez_p.h +++ b/src/bluetooth/qlowenergycontroller_bluez_p.h @@ -202,7 +202,7 @@ private: bool encryptionChangePending; bool receivedMtuExchangeRequest = false; - HciManager *hciManager = nullptr; + std::shared_ptr<HciManager> hciManager; QLeAdvertiser *advertiser = nullptr; QSocketNotifier *serverSocketNotifier = nullptr; QTimer *requestTimer = nullptr; |