[binutils-gdb] bfd: fix memory leak when assigning the merge result of OAv2 string attributes

Matthieu Longo mlongo@sourceware.org
Fri Feb 6 10:42:25 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=2eeb2c99bb0fff2ff0afab5959a4c49c87035aab

commit 2eeb2c99bb0fff2ff0afab5959a4c49c87035aab
Author: Matthieu Longo <matthieu.longo@arm.com>
Date:   Mon Feb 2 14:40:22 2026 +0000

    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:
---
 bfd/elf-attrs.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

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;
     }


More information about the Binutils-cvs mailing list