Anchor all four wrap symbols, add 2-slot coverage, log outside the lock

This commit is contained in:
J. Nick Koston
2026-08-10 16:09:17 -05:00
parent 03a39597e8
commit 5b7a6d4e81
5 changed files with 49 additions and 8 deletions
@@ -973,8 +973,10 @@ int RP2GattClient::gatt_disconnect() {
}
uint8_t status = ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
if (this->con_handle_ != HCI_CON_HANDLE_INVALID) {
BluetoothLock lock;
status = gap_disconnect(this->con_handle_);
{
BluetoothLock lock;
status = gap_disconnect(this->con_handle_);
}
if (status != 0) {
ESP_LOGW(TAG, "[%u] gap_disconnect failed, status=0x%02x", this->engine_index_, status);
}
@@ -60,17 +60,28 @@ struct PoolInit {
} // namespace
// Exact semantics of btstack_memory.c's static-pool arm: zeroed block on
// success, NULL when exhausted; free returns the block to the pool.
// success, NULL when exhausted; free returns the block to the pool. The
// prebuilt pools stay resident in .bss (~7.4 KB, kept live by
// btstack_memory_init in the archive) — dead weight here, not a leak.
// NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming)
extern "C" gatt_client_t *__real_btstack_memory_gatt_client_get(void);
extern "C" void __real_btstack_memory_gatt_client_free(gatt_client_t *gatt_client);
extern "C" hci_connection_t *__real_btstack_memory_hci_connection_get(void);
extern "C" void __real_btstack_memory_hci_connection_free(hci_connection_t *hci_connection);
namespace {
// Never called: the linker silently ignores --wrap for an unreferenced
// symbol, and __real_* only resolves while --wrap is in effect — so this
// reference turns "pools compiled but flags not emitted" into a link error
// instead of a silent fallback to the prebuilt one-client pool.
// symbol, and __real_* only resolves while --wrap is in effect — so these
// references turn "pools compiled but a flag not emitted" into a link error
// instead of a silent fallback to the prebuilt one-client pool. One anchor
// per wrapped symbol, so dropping any single flag fails loudly.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
[[gnu::used]] gatt_client_t *(*const WRAP_ACTIVE_CHECK)() = &__real_btstack_memory_gatt_client_get;
[[gnu::used]] void (*const WRAP_ACTIVE_CHECKS[])() = {
reinterpret_cast<void (*)()>(&__real_btstack_memory_gatt_client_get),
reinterpret_cast<void (*)()>(&__real_btstack_memory_gatt_client_free),
reinterpret_cast<void (*)()>(&__real_btstack_memory_hci_connection_get),
reinterpret_cast<void (*)()>(&__real_btstack_memory_hci_connection_free),
};
} // namespace
extern "C" {
@@ -0,0 +1,16 @@
esphome:
name: poolwrap-rp2-two
rp2:
board: rpipicow
wifi:
ssid: MySSID
password: password1
api:
rp2_ble_tracker:
bluetooth_proxy:
connection_slots: 2
@@ -27,6 +27,17 @@ def test_default_slots_emit_the_pool_wrap(
assert get_define_value("BLUETOOTH_PROXY_MAX_CONNECTIONS") == "3"
def test_two_slots_emit_the_pool_wrap(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
# Two slots: the wrap pools are smaller than the cap, sized from the count.
generate_main(component_config_path("rp2_proxy_two_slots.yaml"))
assert all(flag in CORE.build_flags for flag in WRAP_FLAGS)
assert get_define_value("ESPHOME_BLE_GATT_CLIENT_COUNT") == "2"
assert get_define_value("BLUETOOTH_PROXY_MAX_CONNECTIONS") == "2"
def test_single_slot_keeps_the_prebuilt_pools(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
@@ -6,6 +6,7 @@ packages:
rp2_ble_tracker:
# Two slots: the one shape where the wrap pools are smaller than the cap.
bluetooth_proxy:
active: true
connection_slots: 3
connection_slots: 2