Commit: Free more bfds on linker exit

Nick Clifton nickc@redhat.com
Wed Feb 4 11:38:04 GMT 2026


Hi Guys,

  I am applying the patch below to close on the big memory leaks in the
  linker.  After applying the patch the largest lost block of memory
  went from 311 megabytes to 227 kilobytes.  (This information was
  obtained by using valgrind to the monitor the linker whilst it linked
  LLVM's llc binary.  LLC is a 2 gigabyte executable so this makes for a
  nice big test).

  The patch does not actually help with my ultimate goal of reducing the
  linker's overall memory usage.  But it does feel good to close such a
  big leak and maybe it will be possible to call the new cleanup
  function earlier on in the link process.

Cheers
  Nick
  
diff --git a/ld/ldlang.c b/ld/ldlang.c
index c0d729811ec..a8c7854b5f8 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1427,6 +1427,37 @@ lang_finish (void)
   ldfile_free ();
 }
 
+/* Called by ld_cleanup() at linker exit.  Frees any remaining memory used by
+   ldlang.c in order to pacify memory leak checkers.  */
+
+void
+lang_cleanup (void)
+{
+  lang_input_statement_type *search;
+
+  /* FIXME: Walking the file_chain list closes most of the open bfds but not
+     all of them.  We should find and close the others as well.
+
+     Note: the bfds closed here can also be found on the input_file_chain and
+     link_info.input_bfd lists.  A bfd can only be closed once however, so we
+     must not walk those other lists.  */
+
+  for (search = (void *) file_chain.head;
+       search != NULL;
+       search = search->next_real_file)
+    {
+      if (search->the_bfd == NULL)
+	continue;
+      
+      bfd_close_all_done (search->the_bfd);
+      search->the_bfd = NULL;
+    }
+
+  stat_free (NULL);
+
+  obstack_free (&pt_obstack, NULL);
+}
+
 /*----------------------------------------------------------------------
   A region is an area of memory declared with the
   MEMORY {  name:org=exp, len=exp ... }
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 36f3c03955d..c3ee40a980c 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -546,6 +546,8 @@ extern void lang_init
   (bool);
 extern void lang_finish
   (void);
+extern void lang_cleanup
+  (void);
 extern lang_memory_region_type * lang_memory_region_lookup
   (const char * const, bool);
 extern void lang_memory_region_alias
diff --git a/ld/ldmain.c b/ld/ldmain.c
index a2711d230ea..c73c228e59d 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -222,14 +222,11 @@ write_dependency_file (void)
 static void
 ld_cleanup (void)
 {
-  bfd *ibfd, *inext;
   if (link_info.output_bfd)
     bfd_close_all_done (link_info.output_bfd);
-  for (ibfd = link_info.input_bfds; ibfd; ibfd = inext)
-    {
-      inext = ibfd->link.next;
-      bfd_close_all_done (ibfd);
-    }
+
+  lang_cleanup ();
+
   /* Note - we do not call ld_plugin_start (PHASE_PLUGINS) here as this
      function is only called when the linker is exiting - ie after any
      stats may have been reported, and potentially in the middle of a



More information about the Binutils mailing list