Skip to content

RDKBWIFI-498: Fix EM subdoc memory leaks in webconfig decode and EM a…#1250

Open
dkyncu wants to merge 1 commit into
rdkcentral:developfrom
dkyncu:leak-fixes
Open

RDKBWIFI-498: Fix EM subdoc memory leaks in webconfig decode and EM a…#1250
dkyncu wants to merge 1 commit into
rdkcentral:developfrom
dkyncu:leak-fixes

Conversation

@dkyncu

@dkyncu dkyncu commented Jul 6, 2026

Copy link
Copy Markdown

…pp publishers

The EasyMesh AP metrics pipeline leaks on both ends of the webconfig subdoc exchange, growing the consumer of the report (EM agent, via libwifi_webconfig) and OneWifi itself on every reporting interval. Leaks were located with LeakSanitizer and validated fixed on a device (RSS flat over 8 hours).

Decode side (libwifi_webconfig):

  • decode_em_ap_metrics_report_subdoc never freed data->u.encoded.json; per framework convention (see decode_radio_subdoc) the subdoc decoder owns the parsed tree, so the whole cJSON tree of every report leaked. Delete it on the success path and on the two error paths that were missing it.

  • decode_em_ap_metrics_report_object mallocs per-vap sta_traffic_stats and sta_link_metrics arrays into the decoded params, but nothing on the decode/translate path freed them (webconfig_data_free only frees u.encoded.raw). Free them in webconfig_easymesh_decode after translation, mirroring the existing assoc-map cleanup.

EM app publishers (wifi_em.c):

  • All four publishers (AP metrics report, sta link metrics report, channel scan report, beacon report) leaked the encoded JSON string: webconfig_encode allocates data->u.encoded.raw, the bus publish copies the payload, and the cleanup paths freed the decoded members and data but never the encoded string. The beacon report publisher also leaked wb_data itself on the success path.

Copilot AI review requested due to automatic review settings July 6, 2026 17:34
@dkyncu
dkyncu requested a review from a team as a code owner July 6, 2026 17:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes memory leaks in the EasyMesh AP metrics reporting pipeline by ensuring both decoded (cJSON tree + per-VAP arrays) and encoded (JSON string) allocations are freed across success/error paths.

Changes:

  • Free parsed cJSON (u.encoded.json) in decode_em_ap_metrics_report_subdoc() on success and additional error paths.
  • Free per-VAP decoded allocations (sta_traffic_stats, sta_link_metrics) after translation in webconfig_easymesh_decode() (EM_APP).
  • Free encoded payload strings (u.encoded.raw) and missing success-path allocations in EasyMesh publishers in wifi_em.c.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
source/webconfig/wifi_webconfig_em_ap_metrics_report.c Deletes decoded cJSON tree to stop per-interval subdoc decode leaks.
source/webconfig/wifi_easymesh_translator.c Adds EM_APP cleanup for decoded per-VAP arrays after translation.
source/apps/em/wifi_em.c Frees encoded JSON strings (and one missing struct free) in multiple EM publishers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread source/apps/em/wifi_em.c
Comment thread source/webconfig/wifi_webconfig_em_ap_metrics_report.c
Comment thread source/webconfig/wifi_webconfig_em_ap_metrics_report.c
Comment thread source/apps/em/wifi_em.c
…pp publishers

The EasyMesh AP metrics pipeline leaks on both ends of the webconfig
subdoc exchange, growing the consumer of the report (EM agent, via
libwifi_webconfig) and OneWifi itself on every reporting interval.
Leaks were located with LeakSanitizer and validated fixed on a device
(RSS flat over 8 hours).

Decode side (libwifi_webconfig):

- decode_em_ap_metrics_report_subdoc never freed data->u.encoded.json;
  per framework convention (see decode_radio_subdoc) the subdoc
  decoder owns the parsed tree, so the whole cJSON tree of every
  report leaked. Delete it on the success path and on the two error
  paths that were missing it.

- decode_em_ap_metrics_report_object mallocs per-vap sta_traffic_stats
  and sta_link_metrics arrays into the decoded params, but nothing on
  the decode/translate path freed them (webconfig_data_free only frees
  u.encoded.raw). Free them in webconfig_easymesh_decode after
  translation, mirroring the existing assoc-map cleanup.

EM app publishers (wifi_em.c):

- All four publishers (AP metrics report, sta link metrics report,
  channel scan report, beacon report) leaked the encoded JSON string:
  webconfig_encode allocates data->u.encoded.raw, the bus publish
  copies the payload, and the cleanup paths freed the decoded members
  and `data` but never the encoded string. The beacon report publisher
  also leaked wb_data itself on the success path.

Signed-off-by: Durmus Koyuncu <durmus.kyncu.kd@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@dkyncu

dkyncu commented Jul 7, 2026

Copy link
Copy Markdown
Author

@Nikita-Hakai

Please review, thanks

*type = webconfig_easymesh_data.type;
//debug_external_protos(&webconfig_easymesh_data, __func__, __LINE__);
#ifdef EM_APP
webconfig_easymesh_free_ap_metrics_report(&webconfig_easymesh_data);

@Nikita-Hakai Nikita-Hakai Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think instead of this, we can cleanup in the corresponding translation function itself, something as below:

diff --git a/source/webconfig/wifi_easymesh_translator.c b/source/webconfig/wifi_easymesh_translator.c
index 5bc7ea4..fd717d1 100644
--- a/source/webconfig/wifi_easymesh_translator.c
+++ b/source/webconfig/wifi_easymesh_translator.c
@@ -1536,6 +1536,8 @@ webconfig_error_t translate_sta_link_metrics_object_to_easy_mesh_sta_info(webcon
 
     if (sta_size == 0) {
         wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d Dev Stats is NULL\n", __func__, __LINE__);
+        free(params->em_sta_link_metrics_rsp.per_sta_metrics);
+        params->em_sta_link_metrics_rsp.per_sta_metrics = NULL;
         return webconfig_error_translate_to_easymesh;
     }
 
@@ -1546,6 +1548,8 @@ webconfig_error_t translate_sta_link_metrics_object_to_easy_mesh_sta_info(webcon
     proto = (webconfig_external_easymesh_t *)params->external_protos;
     if (proto == NULL) {
         wifi_util_error_print(WIFI_WEBCONFIG,"%s:%d: em_sta_info_t is NULL\n", __func__, __LINE__);
+        free(params->em_sta_link_metrics_rsp.per_sta_metrics);
+        params->em_sta_link_metrics_rsp.per_sta_metrics = NULL;
         return webconfig_error_translate_to_easymesh;
     }
 
@@ -1581,6 +1585,13 @@ webconfig_error_t translate_sta_link_metrics_object_to_easy_mesh_sta_info(webcon
             proto->put_sta_info(proto->data_model, em_sta_dev_info, em_target_sta_map_assoc);
         }
     }
+
+    // Free the heap array allocated by decode_em_sta_link_metrics_object.
+    if (params->em_sta_link_metrics_rsp.per_sta_metrics != NULL) {
+        free(params->em_sta_link_metrics_rsp.per_sta_metrics);
+        params->em_sta_link_metrics_rsp.per_sta_metrics = NULL;
+    }
+
     return webconfig_error_none;
 }
 
@@ -1611,17 +1622,17 @@ webconfig_error_t translate_ap_metrics_report_to_easy_mesh_bss_info(webconfig_su
     proto = (webconfig_external_easymesh_t *)data->u.decoded.external_protos;
     if (proto == NULL) {
         wifi_util_error_print(WIFI_WEBCONFIG,"%s:%d: external_protos is NULL\n", __func__, __LINE__);
-        return webconfig_error_translate_to_easymesh;
+        goto cleanup_ap_metrics;
     }
 
     if (proto->get_radio_info(proto->data_model, 0) == NULL) {
         wifi_util_error_print(WIFI_WEBCONFIG,"%s:%d: get_radio_info is NULL\n", __func__, __LINE__);
-        return webconfig_error_translate_to_easymesh;
+        goto cleanup_ap_metrics;
     }
 
     if ((decoded_params->num_radios < MIN_NUM_RADIOS) || (decoded_params->num_radios > MAX_NUM_RADIOS )){
         wifi_util_error_print(WIFI_WEBCONFIG, "%s:%d: Invalid number of radios : %x\n", __func__, __LINE__
, decoded_params->num_radios);
-        return webconfig_error_translate_to_easymesh;
+        goto cleanup_ap_metrics;
     }
 
     em_ap_report = &decoded_params->em_ap_metrics_report;
@@ -1752,7 +1763,27 @@ webconfig_error_t translate_ap_metrics_report_to_easy_mesh_bss_info(webconfig_su
         }
     }
 
-    return webconfig_error_none;
+cleanup_ap_metrics:
+    // Free heap allocations made by decode_em_ap_metrics_report_object for
+    // sta_traffic_stats and sta_link_metrics <E2><80><94> these are only needed during
+    // translation and must be freed here once consumed, including on error paths.
+    if (em_ap_report != NULL) {
+        for (unsigned int i = 0; i < em_ap_report->radio_count; i++) {
+            for (int k = 0; k < MAX_NUM_VAP_PER_RADIO; k++) {
+                em_vap_metrics_t *vap_m = &em_ap_report->radio_reports[i].vap_reports[k];
+                if (vap_m->sta_traffic_stats != NULL) {
+                    free(vap_m->sta_traffic_stats);
+                    vap_m->sta_traffic_stats = NULL;
+                }
+                if (vap_m->sta_link_metrics != NULL) {
+                    free(vap_m->sta_link_metrics);
+                    vap_m->sta_link_metrics = NULL;
+                }
+            }
+        }
+    }
+
+    return (em_ap_report != NULL) ? webconfig_error_none : webconfig_error_translate_to_easymesh;
 }
 #endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If its urgent to be merged, we can bring this change as a seperate PR too!

@Nikita-Hakai Nikita-Hakai added the community contribution Contributions from community. label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community contribution Contributions from community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants