From 700c360f1711f487eba9ec95e1216b865020cb21 Mon Sep 17 00:00:00 2001 From: Roman Fordinal Date: Fri, 4 Sep 2026 19:19:46 +0200 Subject: [PATCH] host: do not deinit ble_hs_timer while its event may be queued ble_hs_stop_begin() sets ble_hs_enabled_state to STOPPING and then calls ble_hs_timer_resched() on the next line. ble_hs_is_enabled() only returns true for _ON, so ble_hs_timer_reset() takes the disabled branch and calls ble_npl_callout_deinit(), which on the FreeRTOS port runs ble_npl_event_deinit(&co->ev) and memsets the callout. That clears ev.fn. If the timer had already expired, its ev is already on g_eventq_dflt. The memset does not remove it from the queue, so nimble_port_run() dequeues it and calls a NULL ev->fn. On Xtensa this is a CPU exception with pc 0 and the host task is gone. Removing the call leaks nothing: ble_hs_deinit() already ends with ble_npl_callout_deinit(&ble_hs_timer), which runs after the host has stopped and the queue is drained. Both apache/mynewt-nimble and espressif/esp-nimble call only ble_npl_callout_stop() here. Fixes #1184 --- src/nimble/nimble/host/src/ble_hs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nimble/nimble/host/src/ble_hs.c b/src/nimble/nimble/host/src/ble_hs.c index 8acf6ad91..b32bf1eb4 100644 --- a/src/nimble/nimble/host/src/ble_hs.c +++ b/src/nimble/nimble/host/src/ble_hs.c @@ -444,7 +444,6 @@ ble_hs_timer_reset(uint32_t ticks) if (!ble_hs_is_enabled()) { ble_npl_callout_stop(&ble_hs_timer); - ble_npl_callout_deinit(&ble_hs_timer); } else { rc = ble_npl_callout_reset(&ble_hs_timer, ticks); BLE_HS_DBG_ASSERT_EVAL(rc == 0);