[binutils-gdb] gas: only free on exit when --enable-leak-check
Alan Modra
amodra@sourceware.org
Wed Mar 4 22:47:06 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=eced22e46896200bd76d6ec95eb35a7a1396eb01
commit eced22e46896200bd76d6ec95eb35a7a1396eb01
Author: Alan Modra <amodra@gmail.com>
Date: Thu Mar 5 09:15:04 2026 +1030
gas: only free on exit when --enable-leak-check
Adds a new --enable-leak-check option, controlling whether memory is
freed before exit in order to find memory leaks. The default is to
free memory if BFD_ASAN is non-zero.
* configure.ac: Add new --enable-leak-check..
(ENABLE_LEAK_CHECK): ..defining this.
* as.c (gas_early_init): free_notes on exit only if ENABLE_LEAK_CHECK.
* expr.c (expr_end): Nothing to do when !ENABLE_LEAK_CHECK.
* macro.c (macro_end): Likewise.
* output-file.c (output_file_close): Don't stash frchain obstacks
when !ENABLE_LEAK_CHECK.
* read.c (read_end): Nothing to do when !ENABLE_LEAK_CHECK.
(poend): Likewise.
* stabs.c (stabs_end): Likewise.
* subsegs.c (subsegs_end): Likewise.
* symbols.c (symbol_end): Likewise.
* config/obj-elf-attr.c (oav1_attr_info_exit): Likewise.
* config/obj-elf.c (elf_end): Likewise.
* config/tc-arc.c (arc_md_end): Likewise.
* config/tc-i386.c (i386_md_end): Likewise.
* config/tc-loongarch.c (loongarch_md_end): Likewise.
* config/tc-ppc.c (ppc_md_end): Likewise.
* config/tc-pru.c (pru_md_end): Likewise.
* config/tc-riscv.c (riscv_md_end): Likewise.
* config/tc-tic54x.c (tic54x_md_end): Likewise.
* configure: Regenerate.
* config.in: Regenerate.
Diff:
---
gas/as.c | 3 ++-
gas/config.in | 3 +++
gas/config/obj-elf-attr.c | 3 ++-
gas/config/obj-elf.c | 2 ++
gas/config/tc-arc.c | 2 ++
gas/config/tc-i386.c | 2 ++
gas/config/tc-loongarch.c | 3 ++-
gas/config/tc-ppc.c | 2 ++
gas/config/tc-pru.c | 2 ++
gas/config/tc-riscv.c | 3 ++-
gas/config/tc-tic54x.c | 2 ++
gas/configure | 20 ++++++++++++++++++--
gas/configure.ac | 9 +++++++++
gas/expr.c | 5 +++--
gas/macro.c | 3 ++-
gas/output-file.c | 29 +++++++++++++++++------------
gas/read.c | 5 ++++-
gas/stabs.c | 2 ++
gas/subsegs.c | 2 ++
gas/symbols.c | 3 ++-
20 files changed, 82 insertions(+), 23 deletions(-)
diff --git a/gas/as.c b/gas/as.c
index f08c7c71d73..f33f6ec85cd 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -1330,7 +1330,8 @@ gas_early_init (int *argcp, char ***argvp)
as_fatal (_("libbfd ABI mismatch"));
obstack_begin (¬es, chunksize);
- xatexit (free_notes);
+ if (ENABLE_LEAK_CHECK)
+ xatexit (free_notes);
myname = **argvp;
xmalloc_set_program_name (myname);
diff --git a/gas/config.in b/gas/config.in
index 1bfbee9a348..ae5f41f7058 100644
--- a/gas/config.in
+++ b/gas/config.in
@@ -73,6 +73,9 @@
/* Define if you want run-time sanity checks. */
#undef ENABLE_CHECKING
+/* Define if you want memory to be freed before exit. */
+#undef ENABLE_LEAK_CHECK
+
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
diff --git a/gas/config/obj-elf-attr.c b/gas/config/obj-elf-attr.c
index a731c1f1300..02e474a2c2c 100644
--- a/gas/config/obj-elf-attr.c
+++ b/gas/config/obj-elf-attr.c
@@ -129,7 +129,8 @@ oav1_attr_info_init (void)
void
oav1_attr_info_exit (void)
{
- oav1_attr_info_free (recorded_attributes);
+ if (ENABLE_LEAK_CHECK)
+ oav1_attr_info_free (recorded_attributes);
}
/* Record that we have seen an explicit specification of attribute TAG
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index e09be292cd1..5c44aea0914 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -3005,6 +3005,8 @@ elf_begin (void)
void
elf_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
while (section_stack)
{
struct section_stack *top = section_stack;
diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index d1a5f7e40c6..4e08b563298 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -2722,6 +2722,8 @@ md_begin (void)
void
arc_md_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
htab_delete (arc_opcode_hash);
htab_delete (arc_reg_hash);
htab_delete (arc_aux_hash);
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index ca4523fe2cd..edc44a37345 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -3773,6 +3773,8 @@ i386_print_statistics (FILE *file)
void
i386_md_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
htab_delete (op_hash);
htab_delete (reg_hash);
GOT_symbol = NULL;
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index cce8725485a..716b2f15eea 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -529,7 +529,8 @@ md_begin ()
void
loongarch_md_end (void)
{
- htab_delete (align_hash);
+ if (ENABLE_LEAK_CHECK)
+ htab_delete (align_hash);
}
unsigned long
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index a5dbc73386a..78e5941484c 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -1892,6 +1892,8 @@ md_begin (void)
void
ppc_md_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
if (ppc_hash)
{
htab_delete (ppc_hash);
diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c
index e55ce4790ba..ee86511fafc 100644
--- a/gas/config/tc-pru.c
+++ b/gas/config/tc-pru.c
@@ -1796,6 +1796,8 @@ md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
void
pru_md_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
htab_delete (pru_opcode_hash);
htab_delete (pru_reg_hash);
}
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 6bcf53832a0..ef7c7e3a9a6 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -5782,7 +5782,8 @@ riscv_md_finish (void)
void
riscv_md_end (void)
{
- htab_delete (riscv_pcrel_hi_fixup_hash);
+ if (ENABLE_LEAK_CHECK)
+ htab_delete (riscv_pcrel_hi_fixup_hash);
}
/* Adjust the symbol table. */
diff --git a/gas/config/tc-tic54x.c b/gas/config/tc-tic54x.c
index c6af9bc1803..7b3b0738a1f 100644
--- a/gas/config/tc-tic54x.c
+++ b/gas/config/tc-tic54x.c
@@ -3061,6 +3061,8 @@ md_begin (void)
void
tic54x_md_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
htab_delete (stag_hash);
htab_delete (subsym_recurse_hash);
while (macro_level != -1)
diff --git a/gas/configure b/gas/configure
index e77c440d880..eeace90f375 100755
--- a/gas/configure
+++ b/gas/configure
@@ -816,6 +816,7 @@ enable_plugins
enable_largefile
enable_targets
enable_checking
+enable_leak_check
enable_compressed_debug_sections
enable_default_compressed_debug_sections_algorithm
enable_x86_tls_check
@@ -1488,6 +1489,7 @@ Optional Features:
--disable-largefile omit support for large files
--enable-targets alternative target configurations besides the primary
--enable-checking enable run-time checks
+ --enable-leak-check enable freeing memory before exit
--enable-compressed-debug-sections={all,gas,none}
compress debug sections by default
--enable-default-compressed-debug-sections-algorithm={zlib,zstd}
@@ -11150,7 +11152,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11153 "configure"
+#line 11155 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11256,7 +11258,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11259 "configure"
+#line 11261 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11917,6 +11919,20 @@ $as_echo "#define ENABLE_CHECKING 1" >>confdefs.h
fi
+ac_leak_check=BFD_ASAN
+# Check whether --enable-leak_check was given.
+if test "${enable_leak_check+set}" = set; then :
+ enableval=$enable_leak_check; case "${enableval}" in
+ no) ac_leak_check=0 ;;
+ *) ac_leak_check=1 ;;
+esac
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define ENABLE_LEAK_CHECK ${ac_leak_check}
+_ACEOF
+
+
# PR gas/19109
# Decide the default method for compressing debug sections.
ac_default_compressed_debug_sections=unset
diff --git a/gas/configure.ac b/gas/configure.ac
index 7fb573f8b21..69547f5ffb9 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -62,6 +62,15 @@ if test x$ac_checking != x ; then
AC_DEFINE(ENABLE_CHECKING, 1, [Define if you want run-time sanity checks.])
fi
+ac_leak_check=BFD_ASAN
+AC_ARG_ENABLE(leak_check,
+[ --enable-leak-check enable freeing memory before exit],
+[case "${enableval}" in
+ no) ac_leak_check=0 ;;
+ *) ac_leak_check=1 ;;
+esac])dnl
+AC_DEFINE_UNQUOTED(ENABLE_LEAK_CHECK, ${ac_leak_check}, [Define if you want memory to be freed before exit.])
+
# PR gas/19109
# Decide the default method for compressing debug sections.
ac_default_compressed_debug_sections=unset
diff --git a/gas/expr.c b/gas/expr.c
index c965486bf04..5b6828d391a 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -1640,8 +1640,9 @@ expr_begin (void)
void
expr_end (void)
{
- for (size_t i = 0; i < ARRAY_SIZE (seen); i++)
- free (seen[i]);
+ if (ENABLE_LEAK_CHECK)
+ for (size_t i = 0; i < ARRAY_SIZE (seen); i++)
+ free (seen[i]);
}
/* Return the encoding for the operator at INPUT_LINE_POINTER, and
diff --git a/gas/macro.c b/gas/macro.c
index 76989259feb..65992a7cbbc 100644
--- a/gas/macro.c
+++ b/gas/macro.c
@@ -67,7 +67,8 @@ macro_init (void)
void
macro_end (void)
{
- htab_delete (macro_hash);
+ if (ENABLE_LEAK_CHECK)
+ htab_delete (macro_hash);
}
/* Read input lines till we get to a TO string.
diff --git a/gas/output-file.c b/gas/output-file.c
index 5d5634b1462..6b04e77a6a7 100644
--- a/gas/output-file.c
+++ b/gas/output-file.c
@@ -81,18 +81,23 @@ output_file_close (void)
which will call xexit() which may call this function again... */
stdoutput = NULL;
- /* We can't free obstacks attached to the output bfd sections before
- closing the output bfd since data in those obstacks may need to
- be accessed, but we can't access anything in the output bfd after
- it is closed.. */
- for (sec = obfd->sections; sec; sec = sec->next)
- stash_frchain_obs (sec);
- stash_frchain_obs (reg_section);
- stash_frchain_obs (expr_section);
- stash_frchain_obs (bfd_abs_section_ptr);
- stash_frchain_obs (bfd_und_section_ptr);
- obstack_ptr_grow (¬es, NULL);
- obs = obstack_finish (¬es);
+ if (ENABLE_LEAK_CHECK)
+ {
+ /* We can't free obstacks attached to the output bfd sections before
+ closing the output bfd since data in those obstacks may need to
+ be accessed, but we can't access anything in the output bfd after
+ it is closed.. */
+ for (sec = obfd->sections; sec; sec = sec->next)
+ stash_frchain_obs (sec);
+ stash_frchain_obs (reg_section);
+ stash_frchain_obs (expr_section);
+ stash_frchain_obs (bfd_abs_section_ptr);
+ stash_frchain_obs (bfd_und_section_ptr);
+ obstack_ptr_grow (¬es, NULL);
+ obs = obstack_finish (¬es);
+ }
+ else
+ obs = NULL;
/* Close the bfd. */
if (!flag_always_generate_output && had_errors ())
diff --git a/gas/read.c b/gas/read.c
index bac5bea544c..7a0c73abc5c 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -304,6 +304,8 @@ read_begin (void)
void
read_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
stabs_end ();
poend ();
_obstack_free (&cond_obstack, NULL);
@@ -621,7 +623,8 @@ pobegin (void)
static void
poend (void)
{
- htab_delete (po_hash);
+ if (ENABLE_LEAK_CHECK)
+ htab_delete (po_hash);
}
#define HANDLE_CONDITIONAL_ASSEMBLY(num_read) \
diff --git a/gas/stabs.c b/gas/stabs.c
index c7797bc01e4..0233cc5e018 100644
--- a/gas/stabs.c
+++ b/gas/stabs.c
@@ -673,6 +673,8 @@ stabs_begin (void)
void
stabs_end (void)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
free ((char *) current_function_label);
free (last_asm_file);
free (prev_line_file);
diff --git a/gas/subsegs.c b/gas/subsegs.c
index 199fd869f21..eebd1113c07 100644
--- a/gas/subsegs.c
+++ b/gas/subsegs.c
@@ -47,6 +47,8 @@ subsegs_begin (void)
void
subsegs_end (struct obstack **obs)
{
+ if (!ENABLE_LEAK_CHECK)
+ return;
for (; *obs; obs++)
_obstack_free (*obs, NULL);
_obstack_free (&frchains, NULL);
diff --git a/gas/symbols.c b/gas/symbols.c
index 5ad5dbb2dd9..5844439fd34 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -3150,7 +3150,8 @@ symbol_begin (void)
void
symbol_end (void)
{
- htab_delete (sy_hash);
+ if (ENABLE_LEAK_CHECK)
+ htab_delete (sy_hash);
}
void
More information about the Binutils-cvs
mailing list