From: Matthieu Longo Date: Mon, 2 Feb 2026 14:40:22 +0000 (+0000) Subject: bfd: fix memory leak when assigning the merge result of OAv2 string attributes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2eeb2c99bb0fff2ff0afab5959a4c49c87035aab;p=thirdparty%2Fbinutils-gdb.git bfd: fix memory leak when assigning the merge result of OAv2 string attributes oav2_attr_merge() merges input OAv2 attributes and returns a merge result, which is then assigned to the previous value held by REF. In the current implementation of handle_optional_subsection_merge(), when merging string attributes, the existing value is overwritten without first being freed. This results in a memory leak. This issue was detected by LeakSanitizer (see the relevant stack trace below). This patch fixes the memory leak by wrapping the assignment of the merge result to REF inside a helper function. For string attributes, the helper frees the previous value before performing the assignment. This approach also centralizes the logic and makes easier to correctly free and assign more complex structures in the future, if needed. ==ERROR: LeakSanitizer: detected memory leaks Direct leak of 12 byte(s) in 2 object(s) allocated from: #2 xmemdup ../../libiberty/xmemdup.c:37 #3 read_ntbs ../../bfd/elf-attrs.c:2676 #4 oav2_parse_attr ../../bfd/elf-attrs.c:2699 #5 oav2_parse_subsection ../../bfd/elf-attrs.c:2845 #6 oav2_parse_section ../../bfd/elf-attrs.c:2883 #7 _bfd_elf_parse_attributes ../../bfd/elf-attrs.c:2947 --- diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c index 6c3cfc09677..e0847a04aec 100644 --- a/bfd/elf-attrs.c +++ b/bfd/elf-attrs.c @@ -1061,6 +1061,19 @@ oav2_subsections_mark_unknown (const bfd *abfd) } } +/* Assign the merge result to REF. + The only reason to exist for this helper is when the manipulated value is a + string. In this case, the value in REF must be freed before assigning. */ +static void +oav2_assign_value (obj_attr_encoding_v2_t encoding, + obj_attr_v2_t *a_ref, + union obj_attr_value_v2 res) +{ + if (encoding == OA_ENC_NTBS) + free ((void *) a_ref->val.string); + a_ref->val = res; +} + /* Initialize the given ATTR with its default value coming from the known tag registry. */ static void @@ -1505,7 +1518,7 @@ handle_optional_subsection_merge (const struct bfd_link_info *info, frozen_is_abfd); _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); if (res.merge) - a_ref->val = res.val; + oav2_assign_value (s_ref->encoding, a_ref, res.val); else if (res.reason == OAv2_MERGE_UNSUPPORTED) a_ref->status = obj_attr_v2_unknown; a_ref = a_ref->next; @@ -1518,7 +1531,7 @@ handle_optional_subsection_merge (const struct bfd_link_info *info, frozen_is_abfd); if (res.merge || res.reason == OAv2_MERGE_SAME_VALUE_AS_REF) { - a_default->val = res.val; + oav2_assign_value (s_ref->encoding, a_default, res.val); LINKED_LIST_INSERT_BEFORE (obj_attr_v2_t) (s_ref, a_default, a_ref); } @@ -1532,7 +1545,7 @@ handle_optional_subsection_merge (const struct bfd_link_info *info, = oav2_attr_merge (info, abfd, s_ref, a_ref, a_abfd, a_frozen, frozen_is_abfd); if (res.merge) - a_ref->val = res.val; + oav2_assign_value (s_ref->encoding, a_ref, res.val); else if (res.reason == OAv2_MERGE_UNSUPPORTED) a_ref->status = obj_attr_v2_unknown; a_ref = a_ref->next; @@ -1547,7 +1560,7 @@ handle_optional_subsection_merge (const struct bfd_link_info *info, = oav2_attr_merge (info, abfd, s_ref, a_default, a_abfd, NULL, false); if (res.merge || res.reason == OAv2_MERGE_SAME_VALUE_AS_REF) { - a_default->val = res.val; + oav2_assign_value (s_ref->encoding, a_default, res.val); LINKED_LIST_APPEND (obj_attr_v2_t) (s_ref, a_default); } else @@ -1566,7 +1579,7 @@ handle_optional_subsection_merge (const struct bfd_link_info *info, frozen_is_abfd); _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); if (res.merge) - a_ref->val = res.val; + oav2_assign_value (s_ref->encoding, a_ref, res.val); else if (res.reason == OAv2_MERGE_UNSUPPORTED) a_ref->status = obj_attr_v2_unknown; }