[binutils-gdb] Release bfd_alloc memory in bfd_check_format_matches

Alan Modra amodra@sourceware.org
Sat Jan 4 08:55:00 GMT 2020


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ea933f17c3c6b9fa1daf8d03baa34f7bec855d6c

commit ea933f17c3c6b9fa1daf8d03baa34f7bec855d6c
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Jan 2 17:39:32 2020 +1030

    Release bfd_alloc memory in bfd_check_format_matches
    
    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:
---
 bfd/ChangeLog |  8 ++++++++
 bfd/format.c  | 50 +++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 8291a98..148de79 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,13 @@
 2020-01-04  Alan Modra  <amodra@gmail.com>
 
+	* 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.
+
+2020-01-04  Alan Modra  <amodra@gmail.com>
+
 	* mmo.c (mmo_mkobject): Allocate tdata with bfd_zalloc.
 
 2020-01-04  Alan Modra  <amodra@gmail.com>
diff --git a/bfd/format.c b/bfd/format.c
index 5c30431..e53955e 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;
 }



More information about the Binutils-cvs mailing list