Release bfd_alloc memory in bfd_check_format_matches

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Release bfd_alloc memory in bfd_check_format_matches

Alan Modra-3
It's a little tricky.  We can release any memory back when we have a
match failure, but after a match success which we might want to
preserve for later use the high water mark must change to that of the
matched bfd.

        * format.c (bfd_check_format_matches): Add preserve_match.
        Save initial bfd state in "preserve", matched bfd state in
        "preserve_match".  Save just the first match.  Release
        bfd_alloc memory.  Restore and finish preserved state as
        appropriate on all function exit paths.

diff --git a/bfd/format.c b/bfd/format.c
index 5c30431d7a..e53955eb45 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -219,7 +219,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
   int match_count, best_count, best_match;
   int ar_match_index;
   unsigned int initial_section_id = _bfd_section_id;
-  struct bfd_preserve preserve;
+  struct bfd_preserve preserve, preserve_match;
 
   if (matching != NULL)
     *matching = NULL;
@@ -247,7 +247,10 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
   /* Presume the answer is yes.  */
   abfd->format = format;
   save_targ = abfd->xvec;
-  preserve.marker = NULL;
+
+  preserve_match.marker = NULL;
+  if (!bfd_preserve_save (abfd, &preserve))
+    goto err_ret;
 
   /* If the target type was explicitly specified, just check that target.  */
   if (!abfd->target_defaulted)
@@ -289,6 +292,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
   for (target = bfd_target_vector; *target != NULL; target++)
     {
       const bfd_target *temp;
+      void **high_water;
 
       /* The binary target matches anything, so don't return it when
  searching.  Don't match the plugin target if we have another
@@ -306,6 +310,14 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
  have sections attached, which will confuse the next
  _bfd_check_format call.  */
       bfd_reinit (abfd, initial_section_id);
+      /* Free bfd_alloc memory too.  If we have matched and preserved
+ a target then the high water mark is that much higher.  */
+      if (preserve_match.marker)
+ high_water = &preserve_match.marker;
+      else
+ high_water = &preserve.marker;
+      bfd_release (abfd, *high_water);
+      *high_water = bfd_alloc (abfd, 1);
 
       /* Change BFD's target temporarily.  */
       abfd->xvec = *target;
@@ -332,10 +344,6 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
     match_priority = (*target)->match_priority;
 #endif
 
-  match_targ = temp;
-  if (preserve.marker != NULL)
-    bfd_preserve_finish (abfd, &preserve);
-
   if (abfd->format != bfd_archive
       || (bfd_has_map (abfd)
   && bfd_get_error () != bfd_error_wrong_object_format))
@@ -374,8 +382,12 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
       ar_match_index++;
     }
 
-  if (!bfd_preserve_save (abfd, &preserve))
-    goto err_ret;
+  if (preserve_match.marker == NULL)
+    {
+      match_targ = temp;
+      if (!bfd_preserve_save (abfd, &preserve_match))
+ goto err_ret;
+    }
  }
       else if (bfd_get_error () != bfd_error_wrong_format)
  goto err_ret;
@@ -448,18 +460,23 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
      really shouldn't iterate on live bfd's.  Note that saving the
      whole bfd and restoring it would be even worse; the first thing
      you notice is that the cached bfd file position gets out of sync.  */
-  if (preserve.marker != NULL)
-    bfd_preserve_restore (abfd, &preserve);
+  if (preserve_match.marker != NULL)
+    bfd_preserve_restore (abfd, &preserve_match);
 
   if (match_count == 1)
     {
       abfd->xvec = right_targ;
       /* If we come out of the loop knowing that the last target that
  matched is the one we want, then ABFD should still be in a usable
- state (except possibly for XVEC).  */
+ state (except possibly for XVEC).  This is not just an
+ optimisation.  In the case of plugins a match against the
+ plugin target can result in the bfd being changed such that
+ it no longer matches the plugin target, nor will it match
+ RIGHT_TARG again.  */
       if (match_targ != right_targ)
  {
   bfd_reinit (abfd, initial_section_id);
+  bfd_release (abfd, preserve.marker);
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
     goto err_ret;
   match_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd));
@@ -477,6 +494,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
 
       if (matching_vector)
  free (matching_vector);
+      if (preserve_match.marker != NULL)
+ bfd_preserve_finish (abfd, &preserve_match);
+      bfd_preserve_finish (abfd, &preserve);
 
       /* File position has moved, BTW.  */
       return TRUE;
@@ -491,8 +511,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
       abfd->format = bfd_unknown;
       if (matching_vector)
  free (matching_vector);
-      if (preserve.marker != NULL)
- bfd_preserve_restore (abfd, &preserve);
+      if (preserve_match.marker != NULL)
+ bfd_preserve_finish (abfd, &preserve_match);
+      bfd_preserve_restore (abfd, &preserve);
       return FALSE;
     }
 
@@ -515,6 +536,9 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
     }
   else if (matching_vector)
     free (matching_vector);
+  if (preserve_match.marker != NULL)
+    bfd_preserve_finish (abfd, &preserve_match);
+  bfd_preserve_restore (abfd, &preserve);
   return FALSE;
 }
 

--
Alan Modra
Australia Development Lab, IBM