PR29256, memory leak in obj_elf_section_name
authorAlan Modra <amodra@gmail.com>
Fri, 17 Jun 2022 07:55:53 +0000 (17:25 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 17 Jun 2022 11:40:06 +0000 (21:10 +0930)
When handling section names in quotes obj_elf_section_name calls
demand_copy_C_string, which puts the name on the gas notes obstack.
Such strings aren't usually freed, since obstack_free frees all more
recently allocated objects as well as its arg.  When handling
non-quoted names, obj_elf_section_name mallocs the name.  Due to the
mix of allocation strategies it isn't possible for callers to free
names, if that was desirable.  Partially fix this by always creating
names on the obstack, which is more efficient anyway.  (You still
can't obstack_free on error paths due to the xtensa
tc_canonicalize_section_name.)  Also remove a couple of cases where
the name is dup'd for no good reason as far as I know.

PR 29256
* config/obj-elf.c (obj_elf_section_name): Create name on notes
obstack.
(obj_elf_attach_to_group): Don't strdup group name.
(obj_elf_section): Likewise.
(obj_elf_vendor_attribute): Use xmemdup0 rather than xstrndup.

gas/config/obj-elf.c

index b76853053d59ed8dcac49abf02f095f33371a227..e5ab8514de74cf8bdadadd87e9f4e734eecf58d6 100644 (file)
@@ -1055,28 +1055,32 @@ obj_elf_section_name (void)
          return NULL;
        }
 
-      name = xmemdup0 (input_line_pointer, end - input_line_pointer);
+      obstack_grow0 (&notes, input_line_pointer, end - input_line_pointer);
+      name = obstack_base (&notes);
 
       while (flag_sectname_subst)
         {
          char *subst = strchr (name, '%');
          if (subst && subst[1] == 'S')
            {
-             int oldlen = strlen (name);
-             int substlen = strlen (now_seg->name);
-             int newlen = oldlen - 2 + substlen;
-             char *newname = XNEWVEC (char, newlen + 1);
-             int headlen = subst - name;
-             memcpy (newname, name, headlen);
-             strcpy (newname + headlen, now_seg->name);
-             strcat (newname + headlen, subst + 2);
-             xfree (name);
-             name = newname;
+             size_t head = subst - name;
+             size_t tail = strlen (subst + 2) + 1;
+             size_t slen = strlen (now_seg->name);
+
+             if (slen > 2)
+               {
+                 obstack_blank (&notes, slen - 2);
+                 name = obstack_base (&notes);
+               }
+             memmove (name + head + slen, name + head + 2, tail);
+             memcpy (name + head, now_seg->name, slen);
            }
          else
            break;
        }
 
+      obstack_finish (&notes);
+
 #ifdef tc_canonicalize_section_name
       name = tc_canonicalize_section_name (name);
 #endif
@@ -1104,7 +1108,7 @@ obj_elf_attach_to_group (int dummy ATTRIBUTE_UNUSED)
       return;
     }
 
-  elf_group_name (now_seg) = xstrdup (gname);
+  elf_group_name (now_seg) = gname;
   elf_section_flags (now_seg) |= SHF_GROUP;
 }
 
@@ -1315,7 +1319,7 @@ obj_elf_section (int push)
              const char *now_group = elf_group_name (now_seg);
              if (now_group != NULL)
                {
-                 match.group_name = xstrdup (now_group);
+                 match.group_name = now_group;
                  linkonce = (now_seg->flags & SEC_LINK_ONCE) != 0;
                }
            }
@@ -2019,7 +2023,7 @@ obj_elf_vendor_attribute (int vendor)
       if (i == 0)
        goto bad;
 
-      name = xstrndup (s, i);
+      name = xmemdup0 (s, i);
 
 #ifndef CONVERT_SYMBOLIC_ATTRIBUTE
 #define CONVERT_SYMBOLIC_ATTRIBUTE(a) -1