]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
bfd: fix memory leak when assigning the merge result of OAv2 string attributes
authorMatthieu Longo <matthieu.longo@arm.com>
Mon, 2 Feb 2026 14:40:22 +0000 (14:40 +0000)
committerMatthieu Longo <matthieu.longo@arm.com>
Fri, 6 Feb 2026 10:41:54 +0000 (10:41 +0000)
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

bfd/elf-attrs.c

index 6c3cfc09677c7d79294f1a2c2455cc1379cfb8b3..e0847a04aecf7f0d2a18c4f478b82f595f1fbf8a 100644 (file)
@@ -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;
     }