aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2025-01-11 16:19:09 +1030
committerAlan Modra <amodra@gmail.com>2025-01-20 07:13:46 +1030
commitd4115c2c8d447e297ae353892de89192c1996211 (patch)
tree70735869906bc8702c11e0cca53a847da2fe8b1f
parentf7b0dfe03050f86062b8400f22c2a3e01eb0208c (diff)
downloadbinutils-d4115c2c8d447e297ae353892de89192c1996211.zip
binutils-d4115c2c8d447e297ae353892de89192c1996211.tar.gz
binutils-d4115c2c8d447e297ae353892de89192c1996211.tar.bz2
Replace xmalloc with stat_alloc in ld parser
A few place dealing with ld script handling made some attempt to free memory, but this was generally ignored and would be quite a lot of work to implement. Instead, use the stat_obstack rather than mallocing in many more cases. * ldexp.c (exp_get_fill): Use stat_alloc for fill. * ldfile.c (ldfile_try_open_bfd): Don't free yylval fields. * ldgram.y: Replace xmalloc with stat_alloc throughout. * ldlang.c (stat_memdup, stat_strdup): New functions. (ldirname): Use stat_memdup. Don't strdup ".". (output_section_callback_sort): Use stat_alloc. (output_section_callback_tree_to_list): Don't free. (lang_memory_region_lookup): Use stat_strdup. (lang_memory_region_alias): Likewise. (add_excluded_libs): Use stat_alloc and stat_memdup. (ldlang_add_undef, ldlang_add_require_defined): Use stat_strdup. (lang_add_nocrossref, lang_leave_overlay): Use stat_alloc. (realsymbol): Use stat_strdup for return value and always free symbol. (lang_new_vers_pattern, lang_new_vers_node): Use stat_alloc. (lang_finalize_version_expr_head): Don't free. Delete FIXME. (lang_register_vers_node): Don't free. (lang_add_vers_depend): Use stat_alloc. (lang_do_version_exports_section): Likewise. (lang_add_unique): Use stat_alloc and stat_strdup. (lang_append_dynamic_list): Use stat_alloc. * ldlang.h (stat_memdup, stat_strdup): Declare. * ldlex.l: Replace xstrdup with stat_strdup throughout. Replace xmemdup with stat_memdup too. * lexsup.c (parse_args): Don't free export list or dynamic list.
-rw-r--r--ld/ldexp.c4
-rw-r--r--ld/ldfile.c17
-rw-r--r--ld/ldgram.y21
-rw-r--r--ld/ldlang.c87
-rw-r--r--ld/ldlang.h4
-rw-r--r--ld/ldlex.l23
-rw-r--r--ld/lexsup.c22
7 files changed, 74 insertions, 104 deletions
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 035cef6..87d882e 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -1630,7 +1630,7 @@ exp_get_fill (etree_type *tree, fill_type *def, char *name)
{
unsigned char *dst;
unsigned char *s;
- fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
+ fill = stat_alloc ((len + 1) / 2 + sizeof (*fill) - 1);
fill->size = (len + 1) / 2;
dst = fill->data;
s = (unsigned char *) expld.result.str;
@@ -1655,7 +1655,7 @@ exp_get_fill (etree_type *tree, fill_type *def, char *name)
}
else
{
- fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
+ fill = stat_alloc (4 + sizeof (*fill) - 1);
val = expld.result.value;
fill->data[0] = (val >> 24) & 0xff;
fill->data[1] = (val >> 16) & 0xff;
diff --git a/ld/ldfile.c b/ld/ldfile.c
index 1255150..404af5f 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -438,18 +438,11 @@ ldfile_try_open_bfd (const char *attempt,
if (token == ',')
{
if ((token = yylex ()) != NAME)
- {
- free (arg1);
- continue;
- }
+ continue;
arg2 = yylval.name;
if ((token = yylex ()) != ','
|| (token = yylex ()) != NAME)
- {
- free (arg1);
- free (arg2);
- continue;
- }
+ continue;
arg3 = yylval.name;
token = yylex ();
}
@@ -468,18 +461,12 @@ ldfile_try_open_bfd (const char *attempt,
if (strcmp (arg, lang_get_output_target ()) != 0)
skip = 1;
}
- free (arg1);
- free (arg2);
- free (arg3);
break;
case NAME:
case LNAME:
case VERS_IDENTIFIER:
case VERS_TAG:
- free (yylval.name);
- break;
case INT:
- free (yylval.bigint.str);
break;
}
token = yylex ();
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 6d516db..9bb98de 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -543,7 +543,7 @@ section_name_spec:
sect_flag_list: NAME
{
struct flag_info_list *n;
- n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ n = stat_alloc (sizeof *n);
if ($1[0] == '!')
{
n->with = without_flags;
@@ -561,7 +561,7 @@ sect_flag_list: NAME
| sect_flag_list '&' NAME
{
struct flag_info_list *n;
- n = ((struct flag_info_list *) xmalloc (sizeof *n));
+ n = stat_alloc (sizeof *n);
if ($3[0] == '!')
{
n->with = without_flags;
@@ -582,7 +582,7 @@ sect_flags:
INPUT_SECTION_FLAGS '(' sect_flag_list ')'
{
struct flag_info *n;
- n = ((struct flag_info *) xmalloc (sizeof *n));
+ n = stat_alloc (sizeof *n);
n->flag_list = $3;
n->flags_initialized = false;
n->not_with_flags = 0;
@@ -595,7 +595,7 @@ exclude_name_list:
exclude_name_list wildcard_name
{
struct name_list *tmp;
- tmp = (struct name_list *) xmalloc (sizeof *tmp);
+ tmp = stat_alloc (sizeof *tmp);
tmp->name = $2;
tmp->next = $1;
$$ = tmp;
@@ -604,7 +604,7 @@ exclude_name_list:
wildcard_name
{
struct name_list *tmp;
- tmp = (struct name_list *) xmalloc (sizeof *tmp);
+ tmp = stat_alloc (sizeof *tmp);
tmp->name = $1;
tmp->next = NULL;
$$ = tmp;
@@ -615,7 +615,7 @@ section_name_list:
section_name_list opt_comma section_name_spec
{
struct wildcard_list *tmp;
- tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
+ tmp = stat_alloc (sizeof *tmp);
tmp->next = $1;
tmp->spec = $3;
$$ = tmp;
@@ -624,7 +624,7 @@ section_name_list:
section_name_spec
{
struct wildcard_list *tmp;
- tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
+ tmp = stat_alloc (sizeof *tmp);
tmp->next = NULL;
tmp->spec = $1;
$$ = tmp;
@@ -926,7 +926,7 @@ nocrossref_list:
{
struct lang_nocrossref *n;
- n = (struct lang_nocrossref *) xmalloc (sizeof *n);
+ n = stat_alloc (sizeof *n);
n->name = $1;
n->next = $2;
$$ = n;
@@ -935,7 +935,7 @@ nocrossref_list:
{
struct lang_nocrossref *n;
- n = (struct lang_nocrossref *) xmalloc (sizeof *n);
+ n = stat_alloc (sizeof *n);
n->name = $1;
n->next = $3;
$$ = n;
@@ -1225,8 +1225,7 @@ phdr_opt:
{
struct lang_output_section_phdr_list *n;
- n = ((struct lang_output_section_phdr_list *)
- xmalloc (sizeof *n));
+ n = stat_alloc (sizeof *n);
n->name = $3;
n->used = false;
n->next = $1;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 74c0271..f613fc9 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -188,6 +188,23 @@ stat_alloc (size_t size)
return obstack_alloc (&stat_obstack, size);
}
+void *
+stat_memdup (const void *src, size_t copy_size, size_t alloc_size)
+{
+ void *ret = obstack_alloc (&stat_obstack, alloc_size);
+ memcpy (ret, src, copy_size);
+ if (alloc_size > copy_size)
+ memset ((char *) ret + copy_size, 0, alloc_size - copy_size);
+ return ret;
+}
+
+char *
+stat_strdup (const char *str)
+{
+ size_t len = strlen (str) + 1;
+ return stat_memdup (str, len, len);
+}
+
/* Code for handling simple wildcards without going through fnmatch,
which can be expensive because of charset translations etc. */
@@ -277,15 +294,13 @@ static char *
ldirname (const char *name)
{
const char *base = lbasename (name);
- char *dirname;
while (base > name && IS_DIR_SEPARATOR (base[-1]))
--base;
- if (base == name)
- return strdup (".");
- dirname = strdup (name);
- dirname[base - name] = '\0';
- return dirname;
+ size_t len = base - name;
+ if (len == 0)
+ return ".";
+ return stat_memdup (name, len, len + 1);
}
/* If PATTERN is of the form archive:file, return a pointer to the
@@ -733,7 +748,7 @@ output_section_callback_sort (lang_wild_statement_type *ptr,
if (wont_add_section_p (section, os))
return;
- node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
+ node = stat_alloc (sizeof (*node));
node->left = 0;
node->right = 0;
node->section = section;
@@ -764,8 +779,6 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
if (tree->right)
output_section_callback_tree_to_list (ptr, tree->right, output);
-
- free (tree);
}
@@ -1454,7 +1467,7 @@ lang_memory_region_lookup (const char *const name, bool create)
new_region = stat_alloc (sizeof (lang_memory_region_type));
- new_region->name_list.name = xstrdup (name);
+ new_region->name_list.name = stat_strdup (name);
new_region->name_list.next = NULL;
new_region->next = NULL;
new_region->origin_exp = NULL;
@@ -1509,7 +1522,7 @@ lang_memory_region_alias (const char *alias, const char *region_name)
/* Add alias to region name list. */
n = stat_alloc (sizeof (lang_memory_region_name));
- n->name = xstrdup (alias);
+ n->name = stat_strdup (alias);
n->next = region->name_list.next;
region->name_list.next = n;
}
@@ -2989,11 +3002,9 @@ add_excluded_libs (const char *list)
end = strpbrk (p, ",:");
if (end == NULL)
end = p + strlen (p);
- entry = (struct excluded_lib *) xmalloc (sizeof (*entry));
+ entry = stat_alloc (sizeof (*entry));
entry->next = excluded_libs;
- entry->name = (char *) xmalloc (end - p + 1);
- memcpy (entry->name, p, end - p);
- entry->name[end - p] = '\0';
+ entry->name = stat_memdup (p, end - p, end - p + 1);
excluded_libs = entry;
if (*end == '\0')
break;
@@ -4017,7 +4028,7 @@ ldlang_add_undef (const char *const name, bool cmdline ATTRIBUTE_UNUSED)
new_undef->next = ldlang_undef_chain_list_head;
ldlang_undef_chain_list_head = new_undef;
- new_undef->name = xstrdup (name);
+ new_undef->name = stat_strdup (name);
if (link_info.output_bfd != NULL)
insert_undefined (new_undef->name);
@@ -4096,7 +4107,7 @@ ldlang_add_require_defined (const char *const name)
ldlang_add_undef (name, true);
ptr = stat_alloc (sizeof (*ptr));
ptr->next = require_defined_symbol_list;
- ptr->name = strdup (name);
+ ptr->name = stat_strdup (name);
require_defined_symbol_list = ptr;
}
@@ -9183,7 +9194,7 @@ lang_add_nocrossref (lang_nocrossref_type *l)
{
struct lang_nocrossrefs *n;
- n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
+ n = stat_alloc (sizeof *n);
n->next = nocrossref_list;
n->list = l;
n->onlyfirst = false;
@@ -9366,7 +9377,7 @@ lang_leave_overlay (etree_type *lma_expr,
{
lang_nocrossref_type *nc;
- nc = (lang_nocrossref_type *) xmalloc (sizeof *nc);
+ nc = stat_alloc (sizeof *nc);
nc->name = l->os->name;
nc->next = nocrossref;
nocrossref = nc;
@@ -9546,13 +9557,10 @@ realsymbol (const char *pattern)
if (changed)
{
*s = '\0';
- return symbol;
- }
- else
- {
- free (symbol);
- return pattern;
+ pattern = stat_strdup (symbol);
}
+ free (symbol);
+ return pattern;
}
/* This is called for each variable name or match expression. NEW_NAME is
@@ -9567,7 +9575,7 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
{
struct bfd_elf_version_expr *ret;
- ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
+ ret = stat_alloc (sizeof *ret);
ret->next = orig;
ret->symver = 0;
ret->script = 0;
@@ -9604,7 +9612,8 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
{
struct bfd_elf_version_tree *ret;
- ret = (struct bfd_elf_version_tree *) xcalloc (1, sizeof *ret);
+ ret = stat_alloc (sizeof (*ret));
+ memset (ret, 0, sizeof (*ret));
ret->globals.list = globals;
ret->locals.list = locals;
ret->match = lang_vers_match;
@@ -9686,15 +9695,7 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
}
while (e1 && strcmp (e1->pattern, e->pattern) == 0);
- if (last == NULL)
- {
- /* This is a duplicate. */
- /* FIXME: Memory leak. Sometimes pattern is not
- xmalloced alone, but in larger chunk of memory. */
- /* free (e->pattern); */
- free (e);
- }
- else
+ if (last != NULL)
{
e->next = last->next;
last->next = e;
@@ -9734,7 +9735,6 @@ lang_register_vers_node (const char *name,
{
einfo (_("%X%P: anonymous version tag cannot be combined"
" with other version tags\n"));
- free (version);
return;
}
@@ -9827,7 +9827,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
struct bfd_elf_version_deps *ret;
struct bfd_elf_version_tree *t;
- ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
+ ret = stat_alloc (sizeof *ret);
ret->next = list;
for (t = link_info.version_info; t != NULL; t = t->next)
@@ -9860,7 +9860,7 @@ lang_do_version_exports_section (void)
continue;
len = sec->size;
- contents = (char *) xmalloc (len);
+ contents = stat_alloc (len);
if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len))
einfo (_("%X%P: unable to read .exports section contents\n"), sec);
@@ -9871,8 +9871,6 @@ lang_do_version_exports_section (void)
p = strchr (p, '\0') + 1;
}
- /* Do not free the contents, as we used them creating the regex. */
-
/* Do not include this section in the link. */
sec->flags |= SEC_EXCLUDE | SEC_KEEP;
}
@@ -9936,8 +9934,8 @@ lang_add_unique (const char *name)
if (strcmp (ent->name, name) == 0)
return;
- ent = (struct unique_sections *) xmalloc (sizeof *ent);
- ent->name = xstrdup (name);
+ ent = stat_alloc (sizeof *ent);
+ ent->name = stat_strdup (name);
ent->next = unique_section_list;
unique_section_list = ent;
}
@@ -9960,7 +9958,8 @@ lang_append_dynamic_list (struct bfd_elf_dynamic_list **list_p,
{
struct bfd_elf_dynamic_list *d;
- d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d);
+ d = stat_alloc (sizeof (*d));
+ memset (d, 0, sizeof (*d));
d->head.list = dynamic;
d->match = lang_vers_match;
*list_p = d;
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 91779a5..b074d6f 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -664,6 +664,10 @@ extern void lang_for_each_statement_worker
(void (*) (lang_statement_union_type *), lang_statement_union_type *);
extern void *stat_alloc
(size_t);
+extern void * stat_memdup
+ (const void *, size_t, size_t);
+extern char *stat_strdup
+ (const char *);
extern void strip_excluded_output_sections
(void);
extern void lang_clear_os_map
diff --git a/ld/ldlex.l b/ld/ldlex.l
index e704a97..58eca1b 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -188,7 +188,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
&& (yytext[1] == 'x'
|| yytext[1] == 'X'))
{
- yylval.bigint.str = xstrdup (yytext + 2);
+ yylval.bigint.str
+ = stat_strdup (yytext + 2);
}
return INT;
}
@@ -391,32 +392,32 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
<MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* {
/* Filename without commas, needed to parse mri stuff */
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
<SCRIPT,INPUTLIST>{FILENAMECHAR1}{FILENAMECHAR}* {
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
<INPUTLIST>"="{FILENAMECHAR1}{FILENAMECHAR}* {
/* Filename to be prefixed by --sysroot or when non-sysrooted, nothing. */
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
<INPUTLIST>"-l"{FILENAMECHAR}+ {
- yylval.name = xstrdup (yytext + 2);
+ yylval.name = stat_strdup (yytext + 2);
return LNAME;
}
<EXPRESSION>{SYMBOLNAMECHAR1}{SYMBOLNAMECHAR}* {
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
/* The following rule is to prevent a fill expression on the output
section before /DISCARD/ interpreting the '/' as a divide. */
<EXPRESSION>"/DISCARD/" {
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
<WILD>{WILDCHAR}* {
@@ -431,14 +432,14 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
}
else
{
- yylval.name = xstrdup (yytext);
+ yylval.name = stat_strdup (yytext);
return NAME;
}
}
<SCRIPT,EXPRESSION,WILD,VERS_NODE,INPUTLIST>"\""[^\"]*"\"" {
/* No matter the state, quotes give what's inside. */
- yylval.name = xmemdup (yytext + 1, yyleng - 2, yyleng - 1);
+ yylval.name = stat_memdup (yytext + 1, yyleng - 2, yyleng - 1);
return NAME;
}
@@ -457,10 +458,10 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
<VERS_NODE>extern { RTOKEN(EXTERN); }
-<VERS_NODE>{V_IDENTIFIER} { yylval.name = xstrdup (yytext);
+<VERS_NODE>{V_IDENTIFIER} { yylval.name = stat_strdup (yytext);
return VERS_IDENTIFIER; }
-<VERS_SCRIPT>{V_TAG} { yylval.name = xstrdup (yytext);
+<VERS_SCRIPT>{V_TAG} { yylval.name = stat_strdup (yytext);
return VERS_TAG; }
<VERS_START>"{" { BEGIN(VERS_SCRIPT); return *yytext; }
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 5399aa4..58b9bdd 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1989,16 +1989,6 @@ parse_args (unsigned argc, char **argv)
if (opt_dynamic_list != dynamic_list_data)
opt_dynamic_list = dynamic_list;
}
- else
- {
- /* Free the export list. */
- for (; head->next != NULL; head = next)
- {
- next = head->next;
- free (head);
- }
- free (export_list);
- }
}
switch (opt_dynamic_list)
@@ -2022,17 +2012,7 @@ parse_args (unsigned argc, char **argv)
break;
case symbolic:
link_info.symbolic = true;
- if (link_info.dynamic_list)
- {
- struct bfd_elf_version_expr *ent, *next;
- for (ent = link_info.dynamic_list->head.list; ent; ent = next)
- {
- next = ent->next;
- free (ent);
- }
- free (link_info.dynamic_list);
- link_info.dynamic_list = NULL;
- }
+ link_info.dynamic_list = NULL;
break;
case symbolic_functions:
link_info.dynamic = true;