Anchor the wrap guards from live code and cover the rp2350 link

This commit is contained in:
J. Nick Koston
2026-08-10 16:48:38 -05:00
parent 7bc02eb25a
commit f90027f7c5
3 changed files with 25 additions and 14 deletions
@@ -609,8 +609,11 @@ void RP2GattClient::release_scan_inhibit_() {
void RP2GattClient::fail_connection_(uint8_t reason) {
{
// Timeout escalation can fire with the completion event lost; release the
// stack-wide connect slot so pending engines can proceed (a still-busy
// stack answers them with DISALLOWED and they keep pending).
// stack-wide connect slot so pending engines can proceed. Until the old
// completion is processed, gap_connect answers any peer with DISALLOWED
// (the request-level guard in hci.c); a cancel idles that request
// immediately, and a late addressed completion from the old procedure is
// then dropped by the owner-peer cross-check in the handler.
BluetoothLock lock;
if (connect_owner == this) {
connect_owner = nullptr;
@@ -70,23 +70,19 @@ 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 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]] 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),
};
// Fails the link if the corresponding --wrap flag is missing: __real_* only
// exists while --wrap is in effect, and each wrap function anchors its own
// symbol so dropping any single flag fails loudly. A code reference is used
// because the framework links with --gc-sections, which discards an
// unreferenced data anchor regardless of [[gnu::used]] (and this toolchain
// does not emit SHF_GNU_RETAIN for [[gnu::retain]]).
template<typename T> void anchor_wrap(T *symbol) { asm volatile("" ::"r"(symbol)); }
} // namespace
extern "C" {
gatt_client_t *__wrap_btstack_memory_gatt_client_get(void) {
anchor_wrap(&__real_btstack_memory_gatt_client_get);
void *buffer = btstack_memory_pool_get(&gatt_client_pool);
if (buffer != nullptr) {
memset(buffer, 0, sizeof(gatt_client_t));
@@ -95,10 +91,12 @@ gatt_client_t *__wrap_btstack_memory_gatt_client_get(void) {
}
void __wrap_btstack_memory_gatt_client_free(gatt_client_t *gatt_client) {
anchor_wrap(&__real_btstack_memory_gatt_client_free);
btstack_memory_pool_free(&gatt_client_pool, gatt_client);
}
hci_connection_t *__wrap_btstack_memory_hci_connection_get(void) {
anchor_wrap(&__real_btstack_memory_hci_connection_get);
void *buffer = btstack_memory_pool_get(&hci_connection_pool);
if (buffer != nullptr) {
memset(buffer, 0, sizeof(hci_connection_t));
@@ -107,6 +105,7 @@ hci_connection_t *__wrap_btstack_memory_hci_connection_get(void) {
}
void __wrap_btstack_memory_hci_connection_free(hci_connection_t *hci_connection) {
anchor_wrap(&__real_btstack_memory_hci_connection_free);
btstack_memory_pool_free(&hci_connection_pool, hci_connection);
}
@@ -0,0 +1,9 @@
# Pico 2 W build of the full proxy: links the rp2350 framework archive, so
# the pool --wrap overrides and their per-architecture layout asserts are
# exercised for this chip too (see test.rp2040-ard.yaml for the slot shape).
packages:
common: !include common.yaml
rp2_ble_tracker:
bluetooth_proxy: