]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
bfd: fix memory leak when default-initializing an OAv2 attribute
authorMatthieu Longo <matthieu.longo@arm.com>
Mon, 2 Feb 2026 14:54:55 +0000 (14:54 +0000)
committerMatthieu Longo <matthieu.longo@arm.com>
Fri, 6 Feb 2026 10:41:55 +0000 (10:41 +0000)
To merge an OAv2 attribute, the input values must either be present in
the subsections being merged, or a default value must be created for the
missing ones. Note that this default value is not necessarily null.

In the current implementation of oav2_attr_default(), the default value
is created by copying another attribute provided as a template. As a
result, a string attribute may be copied from the template if it is not
NULL. The copied value is overwritten with whatever default the backend
provides for that attribute.

In oav2_attr_overwrite_with_default(), when no default attribute value
is found in the backend, a string attribute is simply assigned NULL.
This ignores the possibility that the original value may be non-NULL,
and causes the previously allocated memory for the string to be leaked.
This issue was detected by the LeakSanitizer (see the relevant part of
the stack trace below).

This patch fixes the memory leak by freeing the existing value before
assigning NULL to the attribute.

==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 5 byte(s) in 1 object(s) allocated from:
    #2 xstrdup ../../libiberty/xstrdup.c:34
    #3 _bfd_elf_obj_attr_v2_copy ../../bfd/elf-attrs.c:3185
    #4 oav2_attr_default ../../bfd/elf-attrs.c:1109
    #5 handle_optional_subsection_merge ../../bfd/elf-attrs.c:1558

bfd/elf-attrs.c

index e0847a04aecf7f0d2a18c4f478b82f595f1fbf8a..c4f81ba5f6ba569dc173b7391a79971ae2a20069 100644 (file)
@@ -1083,33 +1083,30 @@ oav2_attr_overwrite_with_default (const struct bfd_link_info *info,
 {
   const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
 
+  union obj_attr_value_v2 default_value;
+  memset (&default_value, 0, sizeof (default_value));
+
   const obj_attr_info_t *attr_info
     = _bfd_obj_attr_v2_find_known_by_tag (bed, subsec->name, attr->tag);
   if (attr_info == NULL)
     {
       attr->status = obj_attr_v2_unknown;
-      if (subsec->encoding == OA_ENC_ULEB128)
-       attr->val.uint = 0;
-      else
-       attr->val.string = NULL;
+      oav2_assign_value (subsec->encoding, attr, default_value);
       return;
     }
 
   if (bed->obj_attr_v2_default_value != NULL
       && bed->obj_attr_v2_default_value (info, attr_info, subsec, attr))
-    {}
-  else if (subsec->encoding == OA_ENC_NTBS)
+    return;
+
+  if (subsec->encoding == OA_ENC_NTBS)
     {
-      if (attr->val.string != NULL)
-       {
-         free ((void *) attr->val.string);
-         attr->val.string = NULL;
-       }
       if (attr_info->default_value.string != NULL)
-       attr->val.string = xstrdup (attr_info->default_value.string);
+       default_value.string = xstrdup (attr_info->default_value.string);
     }
   else
-    attr->val.uint = attr_info->default_value.uint;
+    default_value.uint = attr_info->default_value.uint;
+  oav2_assign_value (subsec->encoding, attr, default_value);
 }
 
 /* Create a new attribute with the same key (=tag) as ATTR, and initialized with