From 487de67ff8eb3b4f32ee03b6fc95e2c8b5fc984c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 23 Sep 2025 14:52:37 +0200 Subject: [PATCH] Fix measurement configuration memory leak with stack allocation - Replace heap allocation with stack allocation for seq_arr_t structures - Use proper seq_arr_free() with free functions for ASN.1 structures - Remove unnecessary malloc/free calls for sequence containers - Improve memory safety and performance with automatic cleanup Fixes 128-byte memory leak: Direct leak of 128 byte(s) in 2 object(s) allocated from: /#0 0x7e7f39ab4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 /#1 0x56df8b07312d in SEQUENCE_decode_uper /home/guido/repo/openairinterface5g/develop/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/constr_SEQUENCE_uper.c:37 /#2 0x56df8b056551 in uper_decode /home/guido/repo/openairinterface5g/develop/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/uper_decoder.c:83 /#3 0x56df8a896b1b in get_nr_mtc /home/guido/repo/openairinterface5g/develop/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c:4216 /#4 0x56df8a82feb8 in ue_context_setup_request /home/guido/repo/openairinterface5g/develop/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c:635 /#5 0x56df8a66a298 in nr_initiate_handover /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB_mobility.c:218 /#6 0x56df8a6720af in nr_rrc_trigger_n2_ho_target /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB_mobility.c:526 /#7 0x56df8a5cf338 in rrc_gNB_process_e1_bearer_context_setup_resp /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB.c:2633 /#8 0x56df8a5d28ab in rrc_gnb_task /home/guido/repo/openairinterface5g/develop/openair2/RRC/NR/rrc_gNB.c:3012 /#9 0x7e7f38494ac2 in start_thread nptl/pthread_create.c:442 --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 6 +++++- openair2/RRC/NR/rrc_gNB.c | 28 +++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f76f3ee1d1..d711217fbb 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1121,7 +1121,11 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (rc_A3_seq) { for (int i = 0; i < rc_A3_seq->size; i++) { NR_ReportConfigToAddMod_t *rc_A3 = (NR_ReportConfigToAddMod_t *)seq_arr_at(rc_A3_seq, i); - asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3); + // Create a deep copy of the report config + NR_ReportConfigToAddMod_t *rc_A3_copy = NULL; + int result = asn_copy(&asn_DEF_NR_ReportConfigToAddMod, (void **)&rc_A3_copy, rc_A3); + AssertFatal(result >= 0, "error during asn_copy() of ReportConfigToAddMod\n"); + asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3_copy); } } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index cc766b9d81..2661531c27 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -638,11 +638,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell nr_rrc_du_container_t *du = get_du_by_cell_id((gNB_RRC_INST *)rrc, nr_cellid); DevAssert(du != NULL); f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - NR_ReportConfigToAddMod_t *rc_PER = NULL; - NR_ReportConfigToAddMod_t *rc_A2 = NULL; - seq_arr_t *rc_A3_seq = NULL; - seq_arr_t *neigh_seq = NULL; + if (du->mtc != NULL) { + NR_ReportConfigToAddMod_t *rc_PER = NULL; + NR_ReportConfigToAddMod_t *rc_A2 = NULL; + seq_arr_t rc_A3_seq = {0}; + seq_arr_t neigh_seq = {0}; + seq_arr_init(&rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t)); + seq_arr_init(&neigh_seq, sizeof(nr_neighbour_cell_t)); int scs = get_ssb_scs(cell_info); int band = get_dl_band(cell_info); const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; @@ -657,21 +660,17 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell If no related A3 but there is default add the default one. If default one added once as a report, no need to add it again && duplication. */ - rc_A3_seq = malloc(sizeof(seq_arr_t)); - neigh_seq = malloc(sizeof(seq_arr_t)); - seq_arr_init(rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t)); - seq_arr_init(neigh_seq, sizeof(nr_neighbour_cell_t)); LOG_D(NR_RRC, "Preparing A3 Event Measurement Configuration!\n"); bool default_a3_added = false; // To ensure that the default configuration is only added once for (int i = 0; i < neighbour_cells->size; i++) { nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); if (default_a3_added && neighbourCell->physicalCellId == -1) continue; - seq_arr_push_back(neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t)); + seq_arr_push_back(&neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t)); const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId); if (a3Event) { NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4; - seq_arr_push_back(rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); + seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); if (neighbourCell->physicalCellId == -1) default_a3_added = true; } @@ -681,7 +680,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell rc_PER = prepare_periodic_event_report(rrc->measurementConfiguration.per_event); if (rrc->measurementConfiguration.a2_event) rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event); - return get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, rc_A3_seq, neigh_seq); + + NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq); + + // Clean up sequence arrays + seq_arr_free(&rc_A3_seq, NULL); + seq_arr_free(&neigh_seq, NULL); + + return result; } return NULL; }