This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 1c6ed642bf2 espressif: stop leaking a Wi-Fi interrupt handle on every 
esp_wifi_start()
1c6ed642bf2 is described below

commit 1c6ed642bf2d999816d90c979101decad4c25cab
Author: Felipe Moura <[email protected]>
AuthorDate: Tue Sep 29 18:20:08 2026 -0300

    espressif: stop leaking a Wi-Fi interrupt handle on every esp_wifi_start()
    
    set_intr_wrapper() allocates a new intr_handle_data_t from the kernel
    heap each time the Wi-Fi driver calls it, and the driver calls it on
    every esp_wifi_start() -- twice per start on esp32s3 -- not only the
    first time.  clear_intr_wrapper() is a no-op, so the IRQ still holds the
    handle from the previous start: esp_set_handle() refuses to replace it
    with -EINVAL, the return value is ignored, and the new block is lost.
    
    Any application that stops and restarts Wi-Fi to save power therefore
    loses a few bytes of kernel heap per cycle, without bound.
    
    Look up the vector descriptor first, then reuse the handle already
    registered for the IRQ and only allocate and register one when there is
    none.  A failed descriptor lookup no longer touches the registered
    handle.
    
    The same code is present in the esp32, esp32s2, esp32s3, esp32c3 and
    esp32c6 Wi-Fi adapters; all five are fixed the same way.
    
    Signed-off-by: Felipe Moura <[email protected]>
    Assisted-by: Claude Opus 5.5 <[email protected]>
---
 arch/risc-v/src/esp32c3/esp_wifi_adapter.c     | 35 +++++++++++++++++-------
 arch/risc-v/src/esp32c6/esp_wifi_adapter.c     | 35 +++++++++++++++++-------
 arch/xtensa/src/esp32/esp32_wifi_adapter.c     | 37 +++++++++++++++++---------
 arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c | 37 +++++++++++++++++---------
 arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c | 37 +++++++++++++++++---------
 5 files changed, 125 insertions(+), 56 deletions(-)

diff --git a/arch/risc-v/src/esp32c3/esp_wifi_adapter.c 
b/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
index 30be4f099dc..b95031714a6 100644
--- a/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
+++ b/arch/risc-v/src/esp32c3/esp_wifi_adapter.c
@@ -558,6 +558,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
                              uint32_t intr_num, int32_t intr_prio)
 {
   intr_handle_t handle;
+  vector_desc_t *desc;
   int irq = ESP_SOURCE2IRQ(intr_source);
   esp_err_t err;
 
@@ -569,26 +570,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
   esprv_int_set_priority(intr_num, intr_prio);
   esprv_int_set_type(intr_num, INTR_TYPE_LEVEL);
 
-  handle = kmm_calloc(1, sizeof(intr_handle_data_t));
-  if (handle == NULL)
+  desc = get_desc_for_int(intr_num, cpu_no);
+  if (desc == NULL)
     {
-      wlerr("Failed to kmm_calloc\n");
+      wlerr("get_desc_for_int failed\n");
       return;
     }
 
-  handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
-  if (handle->vector_desc == NULL)
+  /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+   * the first one, and nothing clears the handle in between (see
+   * clear_intr_wrapper()).  Reuse the registered handle: a new one would
+   * be refused by esp_set_handle() and leaked.
+   */
+
+  handle = esp_get_handle(cpu_no, irq);
+  if (handle == IRQ_UNMAPPED)
     {
-      wlerr("get_desc_for_int failed\n");
-      kmm_free(handle);
-      return;
+      handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+      if (handle == NULL)
+        {
+          wlerr("Failed to kmm_calloc\n");
+          return;
+        }
+
+      /* Register the handle - it contains all needed information
+       * (cpuint, cpu)
+       */
+
+      esp_set_handle(cpu_no, irq, handle);
     }
 
+  handle->vector_desc = desc;
   handle->vector_desc->source = intr_source;
   handle->shared_vector_desc = NULL;
 
-  esp_set_handle(cpu_no, irq, handle);
-
   err = esp_intr_set_in_iram(handle, false);
   if (err != ESP_OK)
     {
diff --git a/arch/risc-v/src/esp32c6/esp_wifi_adapter.c 
b/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
index f770a0f2e2b..c18f7122f37 100644
--- a/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
+++ b/arch/risc-v/src/esp32c6/esp_wifi_adapter.c
@@ -591,6 +591,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
                              uint32_t intr_num, int32_t intr_prio)
 {
   intr_handle_t handle;
+  vector_desc_t *desc;
   int irq = ESP_SOURCE2IRQ(intr_source);
   esp_err_t err;
 
@@ -602,26 +603,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
   esprv_int_set_priority(intr_num, intr_prio);
   esprv_int_set_type(intr_num, INTR_TYPE_LEVEL);
 
-  handle = kmm_calloc(1, sizeof(intr_handle_data_t));
-  if (handle == NULL)
+  desc = get_desc_for_int(intr_num, cpu_no);
+  if (desc == NULL)
     {
-      wlerr("Failed to kmm_calloc\n");
+      wlerr("get_desc_for_int failed\n");
       return;
     }
 
-  handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
-  if (handle->vector_desc == NULL)
+  /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+   * the first one, and nothing clears the handle in between (see
+   * clear_intr_wrapper()).  Reuse the registered handle: a new one would
+   * be refused by esp_set_handle() and leaked.
+   */
+
+  handle = esp_get_handle(cpu_no, irq);
+  if (handle == IRQ_UNMAPPED)
     {
-      wlerr("get_desc_for_int failed\n");
-      kmm_free(handle);
-      return;
+      handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+      if (handle == NULL)
+        {
+          wlerr("Failed to kmm_calloc\n");
+          return;
+        }
+
+      /* Register the handle - it contains all needed information
+       * (cpuint, cpu)
+       */
+
+      esp_set_handle(cpu_no, irq, handle);
     }
 
+  handle->vector_desc = desc;
   handle->vector_desc->source = intr_source;
   handle->shared_vector_desc = NULL;
 
-  esp_set_handle(cpu_no, irq, handle);
-
   err = esp_intr_set_in_iram(handle, false);
   if (err != ESP_OK)
     {
diff --git a/arch/xtensa/src/esp32/esp32_wifi_adapter.c 
b/arch/xtensa/src/esp32/esp32_wifi_adapter.c
index 2b60394f1d7..0bbf485a303 100644
--- a/arch/xtensa/src/esp32/esp32_wifi_adapter.c
+++ b/arch/xtensa/src/esp32/esp32_wifi_adapter.c
@@ -1765,6 +1765,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
                           uint32_t intr_num, int32_t intr_prio)
 {
   intr_handle_t handle;
+  vector_desc_t *desc;
   int irq = ESP_SOURCE2IRQ(intr_source);
   esp_err_t err;
 
@@ -1774,28 +1775,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
 
   esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
 
-  handle = kmm_calloc(1, sizeof(intr_handle_data_t));
-  if (handle == NULL)
+  desc = get_desc_for_int(intr_num, cpu_no);
+  if (desc == NULL)
     {
-      wlerr("Failed to kmm_calloc\n");
+      wlerr("get_desc_for_int failed\n");
       return;
     }
 
-  handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
-  if (handle->vector_desc == NULL)
+  /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+   * the first one, and nothing clears the handle in between (see
+   * clear_intr_wrapper()).  Reuse the registered handle: a new one would
+   * be refused by esp_set_handle() and leaked.
+   */
+
+  handle = esp_get_handle(cpu_no, irq);
+  if (handle == IRQ_UNMAPPED)
     {
-      wlerr("get_desc_for_int failed\n");
-      kmm_free(handle);
-      return;
+      handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+      if (handle == NULL)
+        {
+          wlerr("Failed to kmm_calloc\n");
+          return;
+        }
+
+      /* Register the handle - it contains all needed information
+       * (cpuint, cpu)
+       */
+
+      esp_set_handle(cpu_no, irq, handle);
     }
 
+  handle->vector_desc = desc;
   handle->vector_desc->source = intr_source;
   handle->shared_vector_desc = NULL;
 
-  /* Register the handle - it contains all needed information (cpuint, cpu) */
-
-  esp_set_handle(cpu_no, irq, handle);
-
   err = esp_intr_set_in_iram(handle, false);
   if (err != OK)
     {
diff --git a/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c 
b/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
index 58fea3062b2..bc1a44a7a66 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_wifi_adapter.c
@@ -1623,6 +1623,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
                           uint32_t intr_num, int32_t intr_prio)
 {
   intr_handle_t handle;
+  vector_desc_t *desc;
   int irq = ESP_SOURCE2IRQ(intr_source);
   esp_err_t err;
 
@@ -1632,28 +1633,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
 
   esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
 
-  handle = kmm_calloc(1, sizeof(intr_handle_data_t));
-  if (handle == NULL)
+  desc = get_desc_for_int(intr_num, cpu_no);
+  if (desc == NULL)
     {
-      wlerr("Failed to kmm_calloc\n");
+      wlerr("get_desc_for_int failed\n");
       return;
     }
 
-  handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
-  if (handle->vector_desc == NULL)
+  /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+   * the first one, and nothing clears the handle in between (see
+   * clear_intr_wrapper()).  Reuse the registered handle: a new one would
+   * be refused by esp_set_handle() and leaked.
+   */
+
+  handle = esp_get_handle(cpu_no, irq);
+  if (handle == IRQ_UNMAPPED)
     {
-      wlerr("get_desc_for_int failed\n");
-      kmm_free(handle);
-      return;
+      handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+      if (handle == NULL)
+        {
+          wlerr("Failed to kmm_calloc\n");
+          return;
+        }
+
+      /* Register the handle - it contains all needed information
+       * (cpuint, cpu)
+       */
+
+      esp_set_handle(cpu_no, irq, handle);
     }
 
+  handle->vector_desc = desc;
   handle->vector_desc->source = intr_source;
   handle->shared_vector_desc = NULL;
 
-  /* Register the handle - it contains all needed information (cpuint, cpu) */
-
-  esp_set_handle(cpu_no, irq, handle);
-
   err = esp_intr_set_in_iram(handle, false);
   if (err != OK)
     {
diff --git a/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c 
b/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
index ca7f5dfced1..278fa70bc3a 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_wifi_adapter.c
@@ -1755,6 +1755,7 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
                              uint32_t intr_num, int32_t intr_prio)
 {
   intr_handle_t handle;
+  vector_desc_t *desc;
   int irq = ESP_SOURCE2IRQ(intr_source);
   esp_err_t err;
 
@@ -1764,28 +1765,40 @@ static void set_intr_wrapper(int32_t cpu_no, uint32_t 
intr_source,
 
   esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num);
 
-  handle = kmm_calloc(1, sizeof(intr_handle_data_t));
-  if (handle == NULL)
+  desc = get_desc_for_int(intr_num, cpu_no);
+  if (desc == NULL)
     {
-      wlerr("Failed to kmm_calloc\n");
+      wlerr("get_desc_for_int failed\n");
       return;
     }
 
-  handle->vector_desc = get_desc_for_int(intr_num, cpu_no);
-  if (handle->vector_desc == NULL)
+  /* The Wi-Fi driver calls this on every esp_wifi_start(), not only on
+   * the first one, and nothing clears the handle in between (see
+   * clear_intr_wrapper()).  Reuse the registered handle: a new one would
+   * be refused by esp_set_handle() and leaked.
+   */
+
+  handle = esp_get_handle(cpu_no, irq);
+  if (handle == IRQ_UNMAPPED)
     {
-      wlerr("get_desc_for_int failed\n");
-      kmm_free(handle);
-      return;
+      handle = kmm_calloc(1, sizeof(intr_handle_data_t));
+      if (handle == NULL)
+        {
+          wlerr("Failed to kmm_calloc\n");
+          return;
+        }
+
+      /* Register the handle - it contains all needed information
+       * (cpuint, cpu)
+       */
+
+      esp_set_handle(cpu_no, irq, handle);
     }
 
+  handle->vector_desc = desc;
   handle->vector_desc->source = intr_source;
   handle->shared_vector_desc = NULL;
 
-  /* Register the handle - it contains all needed information (cpuint, cpu) */
-
-  esp_set_handle(cpu_no, irq, handle);
-
   err = esp_intr_set_in_iram(handle, false);
   if (err != OK)
     {

Reply via email to