ecoff find_nearest_line and final link leaks
authorAlan Modra <amodra@gmail.com>
Thu, 8 Jun 2023 10:25:55 +0000 (19:55 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 9 Jun 2023 03:26:12 +0000 (12:56 +0930)
Freeing ecoff_debug_info "pointers to the unswapped symbolic info"
isn't a simple matter, due to differing allocation strategies.  In
_bfd_ecoff_slurp_symbolic_info the pointers are to objalloc memory.
In the ecoff linker they are to separately malloc'd memory.  In gas we
have most (obj-elf) or all (obj-ecoff) into a single malloc'd buffer.

This patch fixes the leaks for binutils and ld, leaving the gas leaks
for another day.  The mips elf backend already had this covered, and
the ecoff backend had a pointer, raw_syments used as a flag, so most
of the patch is moving these around a little so they are accessible
for both ecoff and elf.

include/
* coff/ecoff.h (struct ecoff_debug_info): Add alloc_syments.
bfd/
* libecoff.h (struct ecoff_tdata): Delete raw_syments.
* elfxx-mips.c (free_ecoff_debug): Delete.  Replace uses with
_bfd_ecoff_free_ecoff_debug_info.
(_bfd_mips_elf_final_link): Init debug.alloc_syments.
* ecofflink.c (_bfd_ecoff_free_ecoff_debug_info): New function.
* ecoff.c (_bfd_ecoff_bfd_free_cached_info): Call
_bfd_ecoff_free_ecoff_debug_info.
(_bfd_ecoff_slurp_symbolic_info): Replace uses of raw_syments
with alloc_syments.
(ecoff_final_link_debug_accumulate): Likewise.  Use
_bfd_ecoff_free_ecoff_debug_info.
(_bfd_ecoff_bfd_copy_private_bfd_data): Set alloc_syments for
copied output.
* elf64-alpha.c (elf64_alpha_read_ecoff_info): Use
_bfd_ecoff_free_ecoff_debug_info.
* libbfd-in.h (_bfd_ecoff_free_ecoff_debug_info): Declare.
* libbfd.h: Regenerate.
gas/
* config/obj-ecoff.c (ecoff_frob_file): Set alloc_syments.
* config/obj-elf.c (elf_frob_file_after_relocs): Likewise.

bfd/ecoff.c
bfd/ecofflink.c
bfd/elf64-alpha.c
bfd/elfxx-mips.c
bfd/libbfd-in.h
bfd/libbfd.h
bfd/libecoff.h
gas/config/obj-ecoff.c
gas/config/obj-elf.c
include/coff/ecoff.h

index f2626c541e24c08b9164d7efd97e2c05bea6c603..522a4425e611d842bd4b674695a17dd75c02a036 100644 (file)
@@ -117,12 +117,15 @@ _bfd_ecoff_bfd_free_cached_info (bfd *abfd)
   if ((bfd_get_format (abfd) == bfd_object
        || bfd_get_format (abfd) == bfd_core)
       && (tdata = ecoff_data (abfd)) != NULL)
-    while (tdata->mips_refhi_list != NULL)
-      {
-       struct mips_hi *ref = tdata->mips_refhi_list;
-       tdata->mips_refhi_list = ref->next;
-       free (ref);
-      }
+    {
+      while (tdata->mips_refhi_list != NULL)
+       {
+         struct mips_hi *ref = tdata->mips_refhi_list;
+         tdata->mips_refhi_list = ref->next;
+         free (ref);
+       }
+      _bfd_ecoff_free_ecoff_debug_info (&tdata->debug_info);
+    }
   return _bfd_generic_bfd_free_cached_info (abfd);
 }
 
@@ -524,7 +527,7 @@ _bfd_ecoff_slurp_symbolic_info (bfd *abfd,
 
   /* Check whether we've already gotten it, and whether there's any to
      get.  */
-  if (ecoff_data (abfd)->raw_syments != NULL)
+  if (debug->alloc_syments)
     return true;
   if (ecoff_data (abfd)->sym_filepos == 0)
     {
@@ -595,7 +598,7 @@ _bfd_ecoff_slurp_symbolic_info (bfd *abfd,
   if (raw == NULL)
     return false;
 
-  ecoff_data (abfd)->raw_syments = raw;
+  debug->alloc_syments = true;
 
   /* Get pointers for the numeric offsets in the HDRR structure.  */
 #define FIX(start, count, ptr, type) \
@@ -1918,6 +1921,9 @@ _bfd_ecoff_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
       oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd;
       oinfo->external_rfd = iinfo->external_rfd;
+
+      /* Flag that oinfo entries should not be freed.  */
+      oinfo->alloc_syments = true;
     }
   else
     {
@@ -3809,9 +3815,9 @@ ecoff_final_link_debug_accumulate (bfd *output_bfd,
       ((char *) debug->ptr)[amt] = 0;                                  \
     } while (0)
 
-  /* If raw_syments is not NULL, then the data was already by read by
+  /* If alloc_syments is true, then the data was already by read by
      _bfd_ecoff_slurp_symbolic_info.  */
-  if (ecoff_data (input_bfd)->raw_syments == NULL)
+  if (!debug->alloc_syments)
     {
       READ (line, cbLineOffset, cbLine, sizeof (unsigned char));
       READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size);
@@ -3833,31 +3839,7 @@ ecoff_final_link_debug_accumulate (bfd *output_bfd,
          input_bfd, debug, swap, info));
 
  return_something:
-  if (ecoff_data (input_bfd)->raw_syments == NULL)
-    {
-      free (debug->line);
-      free (debug->external_dnr);
-      free (debug->external_pdr);
-      free (debug->external_sym);
-      free (debug->external_opt);
-      free (debug->external_aux);
-      free (debug->ss);
-      free (debug->external_fdr);
-      free (debug->external_rfd);
-
-      /* Make sure we don't accidentally follow one of these pointers
-        into freed memory.  */
-      debug->line = NULL;
-      debug->external_dnr = NULL;
-      debug->external_pdr = NULL;
-      debug->external_sym = NULL;
-      debug->external_opt = NULL;
-      debug->external_aux = NULL;
-      debug->ss = NULL;
-      debug->external_fdr = NULL;
-      debug->external_rfd = NULL;
-    }
-
+  _bfd_ecoff_free_ecoff_debug_info (debug);
   return ret;
 }
 
index bba25929f2c82185197ada446c1decbb335d97b9..5b7acd57a1a30e2dd41b838bbe28caf419af199b 100644 (file)
@@ -1696,6 +1696,38 @@ bfd_ecoff_write_accumulated_debug (void * handle,
 /* Handle the find_nearest_line function for both ECOFF and MIPS ELF
    files.  */
 
+/* Free ECOFF debugging info used by find_nearest_line.  */
+
+void
+_bfd_ecoff_free_ecoff_debug_info (struct ecoff_debug_info *debug)
+{
+  if (!debug->alloc_syments)
+    {
+      free (debug->line);
+      free (debug->external_dnr);
+      free (debug->external_pdr);
+      free (debug->external_sym);
+      free (debug->external_opt);
+      free (debug->external_aux);
+      free (debug->ss);
+      free (debug->ssext);
+      free (debug->external_fdr);
+      free (debug->external_rfd);
+      free (debug->external_ext);
+    }
+  debug->line= NULL;
+  debug->external_dnr= NULL;
+  debug->external_pdr= NULL;
+  debug->external_sym= NULL;
+  debug->external_opt= NULL;
+  debug->external_aux= NULL;
+  debug->ss= NULL;
+  debug->ssext= NULL;
+  debug->external_fdr= NULL;
+  debug->external_rfd= NULL;
+  debug->external_ext= NULL;
+}
+
 /* Compare FDR entries.  This is called via qsort.  */
 
 static int
index 5cf9a665ae56c7ca46ca70a28975e32312cf9d38..125379b4f88196035c7c2d011435fff085089c8f 100644 (file)
@@ -1425,17 +1425,7 @@ elf64_alpha_read_ecoff_info (bfd *abfd, asection *section,
 
  error_return:
   free (ext_hdr);
-  free (debug->line);
-  free (debug->external_dnr);
-  free (debug->external_pdr);
-  free (debug->external_sym);
-  free (debug->external_opt);
-  free (debug->external_aux);
-  free (debug->ss);
-  free (debug->ssext);
-  free (debug->external_fdr);
-  free (debug->external_rfd);
-  free (debug->external_ext);
+  _bfd_ecoff_free_ecoff_debug_info (debug);
   return false;
 }
 
index 7d29ec2d10581ea46002b39d89f7088c5a6718e7..a618f6f1249558beea403bced088c16e25d8c1c8 100644 (file)
@@ -1389,35 +1389,6 @@ struct mips_elf_find_line
   struct ecoff_find_line i;
 };
 
-/* Free ECOFF debugging info used by find_nearest_line.  */
-
-static void
-free_ecoff_debug (struct ecoff_debug_info *debug)
-{
-  free (debug->line);
-  free (debug->external_dnr);
-  free (debug->external_pdr);
-  free (debug->external_sym);
-  free (debug->external_opt);
-  free (debug->external_aux);
-  free (debug->ss);
-  free (debug->ssext);
-  free (debug->external_fdr);
-  free (debug->external_rfd);
-  free (debug->external_ext);
-  debug->line = NULL;
-  debug->external_dnr = NULL;
-  debug->external_pdr = NULL;
-  debug->external_sym = NULL;
-  debug->external_opt = NULL;
-  debug->external_aux = NULL;
-  debug->ss = NULL;
-  debug->ssext = NULL;
-  debug->external_fdr = NULL;
-  debug->external_rfd = NULL;
-  debug->external_ext = NULL;
-}
-
 bool
 _bfd_mips_elf_free_cached_info (bfd *abfd)
 {
@@ -1435,7 +1406,7 @@ _bfd_mips_elf_free_cached_info (bfd *abfd)
          free (hi);
        }
       if (tdata->find_line_info != NULL)
-       free_ecoff_debug (&tdata->find_line_info->d);
+       _bfd_ecoff_free_ecoff_debug_info (&tdata->find_line_info->d);
     }
   return _bfd_elf_free_cached_info (abfd);
 }
@@ -1523,7 +1494,7 @@ _bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section,
 
  error_return:
   free (ext_hdr);
-  free_ecoff_debug (debug);
+  _bfd_ecoff_free_ecoff_debug_info (debug);
   return false;
 }
 \f
@@ -13225,7 +13196,7 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asymbol **symbols,
          fi->d.fdr = bfd_alloc (abfd, amt);
          if (fi->d.fdr == NULL)
            {
-             free_ecoff_debug (&fi->d);
+             _bfd_ecoff_free_ecoff_debug_info (&fi->d);
              msec->flags = origflags;
              return false;
            }
@@ -15043,6 +15014,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
          /* We accumulate the debugging information itself in the
             debug_info structure.  */
+         debug.alloc_syments = false;
          debug.line = NULL;
          debug.external_dnr = NULL;
          debug.external_pdr = NULL;
@@ -15128,7 +15100,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                     (mdebug_handle, abfd, &debug, swap, input_bfd,
                      &input_debug, input_swap, info)))
                {
-                 free_ecoff_debug (&input_debug);
+                 _bfd_ecoff_free_ecoff_debug_info (&input_debug);
                  return false;
                }
 
@@ -15171,7 +15143,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                }
 
              /* Free up the information we just read.  */
-             free_ecoff_debug (&input_debug);
+             _bfd_ecoff_free_ecoff_debug_info (&input_debug);
 
              /* Hack: reset the SEC_HAS_CONTENTS flag so that
                 elf_link_input_bfd ignores this section.  */
index ae1b61aa4e3cb71d5d7106d7e4e76522a7ab0023..03ae099c2ea25dcae0e23ae8214c66b80ae0db3f 100644 (file)
@@ -787,6 +787,8 @@ struct ecoff_debug_swap;
 struct ecoff_extr;
 struct ecoff_find_line;
 
+extern void _bfd_ecoff_free_ecoff_debug_info
+  (struct ecoff_debug_info *debug);
 extern bool _bfd_ecoff_locate_line
   (bfd *, asection *, bfd_vma, struct ecoff_debug_info * const,
    const struct ecoff_debug_swap * const, struct ecoff_find_line *,
index 92fbf0195ee16f66e54e5aba823160adda0f1b51..a9fa1111a3de5f1c16cbefebcbd777bc2c37989a 100644 (file)
@@ -793,6 +793,8 @@ struct ecoff_debug_swap;
 struct ecoff_extr;
 struct ecoff_find_line;
 
+extern void _bfd_ecoff_free_ecoff_debug_info
+  (struct ecoff_debug_info *debug);
 extern bool _bfd_ecoff_locate_line
   (bfd *, asection *, bfd_vma, struct ecoff_debug_info * const,
    const struct ecoff_debug_swap * const, struct ecoff_find_line *,
index 0c4bb43c39a9db76d9721a1ec2dd90d9f45209a9..2267c7bc53b787e57620d1794b3216394e393414 100644 (file)
@@ -124,9 +124,6 @@ typedef struct ecoff_tdata
   /* The ECOFF symbolic debugging information.  */
   struct ecoff_debug_info debug_info;
 
-  /* The unswapped ECOFF symbolic information.  */
-  void * raw_syments;
-
   /* The canonical BFD symbols.  */
   struct ecoff_symbol_struct *canonical_symbols;
 
index 092f6f2c927cc454ff3cbc58a839c5559caef752..26da2af01b3f22451705614f57b26691b3db13e6 100644 (file)
@@ -151,6 +151,7 @@ ecoff_frob_file (void)
   ecoff_build_debug (hdr, &buf, debug_swap);
 
   /* Finish up the ecoff_tdata structure.  */
+  ecoff_data (stdoutput)->debug_info.alloc_syments = true;
   set = buf;
 #define SET(ptr, count, type, size) \
   if (hdr->count == 0) \
index bf3ef541ab7b6dcc6c69a9f4dea90c0073df5271..753a929fb141de8a5425fd0f5f9b207ed87759fc 100644 (file)
@@ -3008,6 +3008,7 @@ elf_frob_file_after_relocs (void)
       ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap);
 
       /* Set up the pointers in debug.  */
+      debug.alloc_syments = true;
 #define SET(ptr, offset, type) \
     debug.ptr = (type) (buf + debug.symbolic_header.offset)
 
index 169d8f6918db86fc101c1809ecb5178cc7a3c214..991d92f92dd717c5099d32faa91b18c2832b35ad 100644 (file)
@@ -299,7 +299,10 @@ struct ecoff_debug_info
      all pointers to arrays, not single structures.  They will be NULL
      if there are no instances of the relevant structure.  These
      fields are also used by the assembler to output ECOFF debugging
-     information.  */
+     information.  If alloc_syments is true then the pointers are to
+     objalloc memory, or into a single malloc'd buffer, or otherwise
+     should not be freed.  */
+  bool alloc_syments;
   unsigned char *line;
   void *external_dnr;  /* struct dnr_ext */
   void *external_pdr;  /* struct pdr_ext */