From 4cf7ad9c6320364fe2e95d0e2d19f37d6464faf4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 10 Aug 2026 13:02:27 -0500 Subject: [PATCH] [ble_device_base] Treat a partially bound merger as unbound (#18235) --- .../ble_device_base/scan_response_merger.cpp | 3 ++- .../ble_device_base/test_scan_response_merger.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esphome/components/ble_device_base/scan_response_merger.cpp b/esphome/components/ble_device_base/scan_response_merger.cpp index 15445cee02a..2dd1fd6927e 100644 --- a/esphome/components/ble_device_base/scan_response_merger.cpp +++ b/esphome/components/ble_device_base/scan_response_merger.cpp @@ -8,7 +8,8 @@ namespace esphome::ble_device_base { void ScanResponseMerger::deliver_(const uint8_t *mac, int8_t rssi, uint8_t addr_type, const uint8_t *data, uint8_t data_len, bool raw_only) { - if (this->dispatcher_ == nullptr) + // A partial bind is treated as unbound; never dereference half a binding. + if (this->dispatcher_ == nullptr || this->scan_continuous_ == nullptr) return; this->dispatcher_->dispatch(mac, rssi, addr_type, data, data_len, raw_only, *this->scan_continuous_ ? nullptr : this->log_tag_); diff --git a/tests/components/ble_device_base/test_scan_response_merger.cpp b/tests/components/ble_device_base/test_scan_response_merger.cpp index 013c7bf8f9c..ec157715fd3 100644 --- a/tests/components/ble_device_base/test_scan_response_merger.cpp +++ b/tests/components/ble_device_base/test_scan_response_merger.cpp @@ -179,5 +179,15 @@ TEST_F(ScanResponseMergerTest, UnboundMergerDropsInsteadOfCrashing) { EXPECT_TRUE(unbound.empty()); } +TEST_F(ScanResponseMergerTest, PartialBindIsTreatedAsUnbound) { + ScanResponseMerger partial; + partial.bind(&this->dispatcher_, nullptr, "test"); + std::vector data(20, 0xAA); + partial.submit_scan_rsp(MAC_A, -70, 0, data.data(), data.size()); + partial.stash_adv(MAC_A, -40, 0, data.data(), data.size(), 0); + partial.flush(); // dropped, not dispatched through half a binding + EXPECT_TRUE(this->raw_.frames.empty()); +} + } // namespace } // namespace esphome::ble_device_base::testing