From 6128c09f0b90af95fedc94beb2f6bdadc330714c Mon Sep 17 00:00:00 2001 From: Astha Verma Date: Fri, 13 Feb 2026 21:10:39 +0530 Subject: [PATCH] fix(nimble): Fix memory leak when enabling gatt caching --- nimble/host/src/ble_gatt_priv.h | 2 ++ nimble/host/src/ble_gattc_cache.c | 41 ++++++++++++++++++++++++-- nimble/host/src/ble_gattc_cache_conn.c | 18 +++++------ nimble/host/src/ble_hs.c | 3 ++ 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h index 3391ed178..a4cb9be3c 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -253,6 +253,8 @@ int ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn); int ble_gatts_init(void); #if MYNEWT_VAL(BLE_GATT_CACHING) int ble_gattc_cache_conn_init(); +void ble_gattc_cache_conn_free_mem(); +void ble_gattc_cache_conn_free_all_mem(); #endif #ifdef __cplusplus diff --git a/nimble/host/src/ble_gattc_cache.c b/nimble/host/src/ble_gattc_cache.c index e0d38075a..67f9525ac 100644 --- a/nimble/host/src/ble_gattc_cache.c +++ b/nimble/host/src/ble_gattc_cache.c @@ -879,6 +879,26 @@ ble_gattc_cache_free_mem(void) { if (ble_gattc_cache_static_vars) { if (cache_env) { + uint8_t num_addr = cache_env->num_addr; + if (num_addr > MAX_DEVICE_IN_CACHE) { + num_addr = MAX_DEVICE_IN_CACHE; + } + + /* Close any open per-peer cache handles before releasing cache_env. */ + if (cache_fn.close) { + for (uint8_t i = 0; i < num_addr; i++) { + if (cache_env->cache_addr[i].is_open) { + cache_fn.close(cache_env->cache_addr[i].cache_fp); + cache_env->cache_addr[i].is_open = false; + } + } + + if (cache_env->is_open) { + cache_fn.close(cache_env->addr_fp); + cache_env->is_open = false; + } + } + nimble_platform_mem_free(cache_env); cache_env = NULL; } @@ -898,6 +918,7 @@ ble_gattc_cache_init(void *storage_cb) uint8_t *p_buf = NULL; #if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) + int no_cached_blob = 0; rc = ble_gattc_cache_static_vars_init(); if (rc != 0) { return rc; @@ -936,6 +957,17 @@ ble_gattc_cache_init(void *storage_cb) BLE_HS_LOG(DEBUG, "%s, Line = %d, storage flash get blob data fail, err_code = 0x%x", __func__, __LINE__, rc); } +#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) + /* + * rc == 0x1102 indicates NVS key not found. + * This is expected scenario during first boot or + * when no GATT cache exists yet and should not + * be treated as a fatal error. + */ + if (rc == 0x1102){ + no_cached_blob = 1; + } +#endif goto error; } @@ -971,12 +1003,17 @@ error: p_buf = NULL; } if (cache_env) { + /* Close NVS handle if it was opened before freeing cache_env */ + if (cache_env->is_open && cache_fn.close) { + cache_fn.close(cache_env->addr_fp); + cache_env->is_open = false; + } nimble_platform_mem_free(cache_env); cache_env = NULL; } - #if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) - if (ble_gattc_cache_static_vars) { +#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) + if (ble_gattc_cache_static_vars && !no_cached_blob) { nimble_platform_mem_free(ble_gattc_cache_static_vars); ble_gattc_cache_static_vars = NULL; } diff --git a/nimble/host/src/ble_gattc_cache_conn.c b/nimble/host/src/ble_gattc_cache_conn.c index c3d33cab1..de5edbf72 100644 --- a/nimble/host/src/ble_gattc_cache_conn.c +++ b/nimble/host/src/ble_gattc_cache_conn.c @@ -185,9 +185,6 @@ ble_gattc_cache_conn_disc_dscs(struct ble_gattc_cache_conn *peer); #endif #if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) -void -ble_gattc_cache_conn_free_mem(void); - static ble_gattc_cache_conn_static_vars_t * ble_gattc_cache_conn_static_vars_init(void) { @@ -1466,10 +1463,6 @@ ble_gattc_cache_conn_broken(uint16_t conn_handle) } os_memblock_put(&ble_gattc_cache_conn_pool, conn); - -#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) - ble_gattc_cache_conn_free_mem(); -#endif } void @@ -2244,7 +2237,14 @@ ble_gattc_cache_conn_free_mem(void) nimble_platform_mem_free(ble_gattc_cache_conn_static_vars); ble_gattc_cache_conn_static_vars = NULL; } +#endif +} +void +ble_gattc_cache_conn_free_all_mem(void) +{ + ble_gattc_cache_conn_free_mem(); +#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) ble_gattc_cache_free_mem(); #endif } @@ -2274,7 +2274,7 @@ ble_gattc_cache_conn_init() max_dscs = (MYNEWT_VAL(BLE_GATT_CACHING_MAX_CONNS)) * (MYNEWT_VAL(BLE_GATT_CACHING_MAX_DSCS)); /* Free memory first in case this function gets called more than once. */ - ble_gattc_cache_conn_free_mem(); + ble_gattc_cache_conn_free_all_mem(); #if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) if (ble_gattc_cache_conn_static_vars == NULL) { @@ -2377,7 +2377,7 @@ ble_gattc_cache_conn_init() return 0; err: - ble_gattc_cache_conn_free_mem(); + ble_gattc_cache_conn_free_all_mem(); return rc; } diff --git a/nimble/host/src/ble_hs.c b/nimble/host/src/ble_hs.c index 65aa1daed..8153d43d0 100644 --- a/nimble/host/src/ble_hs.c +++ b/nimble/host/src/ble_hs.c @@ -1100,6 +1100,9 @@ ble_hs_deinit(void) #if MYNEWT_VAL(BLE_GATTC) || MYNEWT_VAL(BLE_GATTS) ble_gattc_deinit(); #endif +#if MYNEWT_VAL(BLE_GATT_CACHING) + ble_gattc_cache_conn_free_all_mem(); +#endif ble_l2cap_deinit();