From 004798130adf0f765287d200a4f5d6322e7ff950 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Tue, 24 Mar 2026 23:04:00 +0530 Subject: [PATCH] fix(data_model): unlink cluster from endpoint on cluster::destroy cluster::destroy() freed the cluster memory and its children (attributes, commands, events) but never removed the cluster from the parent endpoint's linked list, leaving a dangling pointer. This caused use-after-free crashes when creating a new cluster on the same endpoint after destroying one. Fix: look up the parent endpoint via the endpoint_id stored in the cluster struct and unlink before freeing, consistent with how attribute::destroy, command::destroy and event::destroy handle their parent lists. --- .../esp_matter/data_model/esp_matter_data_model.cpp | 9 +++++++-- components/esp_matter/data_model/esp_matter_data_model.h | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/components/esp_matter/data_model/esp_matter_data_model.cpp b/components/esp_matter/data_model/esp_matter_data_model.cpp index 560cbdb59..5f19883d3 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.cpp +++ b/components/esp_matter/data_model/esp_matter_data_model.cpp @@ -1409,8 +1409,13 @@ esp_err_t destroy(cluster_t *cluster) current_cluster->matter_attributes = NULL; } - /* Free */ - esp_matter_mem_free(current_cluster); + /* Remove from parent endpoint's cluster list and free */ + _endpoint_t *parent_endpoint = (_endpoint_t *)endpoint::get(current_cluster->endpoint_id); + if (parent_endpoint) { + SinglyLinkedList<_cluster_t>::remove(&parent_endpoint->cluster_list, current_cluster); + } else { + esp_matter_mem_free(current_cluster); + } return ESP_OK; } diff --git a/components/esp_matter/data_model/esp_matter_data_model.h b/components/esp_matter/data_model/esp_matter_data_model.h index 6917ad345..eaf1ce240 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.h +++ b/components/esp_matter/data_model/esp_matter_data_model.h @@ -447,8 +447,8 @@ cluster_t *create(endpoint_t *endpoint, uint32_t cluster_id, uint8_t flags); /** Destroy cluster * - * This will destroy the cluster which has been created and added to the endpoint. It also destroys the associated - * attributes, commands and events. + * This will remove the cluster from the parent endpoint's cluster list, then destroy the cluster + * and free its associated attributes, commands and events. * * @param[in] cluster Cluster handle. *