diff options
author | Alan Modra <amodra@gmail.com> | 2025-01-11 16:19:09 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2025-01-20 07:13:46 +1030 |
commit | d4115c2c8d447e297ae353892de89192c1996211 (patch) | |
tree | 70735869906bc8702c11e0cca53a847da2fe8b1f | |
parent | f7b0dfe03050f86062b8400f22c2a3e01eb0208c (diff) | |
download | binutils-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.c | 4 | ||||
-rw-r--r-- | ld/ldfile.c | 17 | ||||
-rw-r--r-- | ld/ldgram.y | 21 | ||||
-rw-r--r-- | ld/ldlang.c | 87 | ||||
-rw-r--r-- | ld/ldlang.h | 4 | ||||
-rw-r--r-- | ld/ldlex.l | 23 | ||||
-rw-r--r-- | ld/lexsup.c | 22 |
7 files changed, 74 insertions, 104 deletions
@@ -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 @@ -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; |