More fault tolerant rebase (was Re: libtcl8.5.dll collides with Cygwin DLL by default)

Corinna Vinschen corinna-cygwin@cygwin.com
Tue Mar 13 13:05:00 GMT 2012


On Mar  9 21:30, Corinna Vinschen wrote:
> On Mar  8 10:12, Corinna Vinschen wrote:
> > What rebase *should* do is to mark the DLLs as blocked, and keep them in
> > the list together with their current address and size, so it can arrange
> > the addresses of the other DLLs, taking the blocked address space into
> > account, just like it does with the Cygwin DLL.  And of course, the DLL
> > should not be removed from the database.
> > 
> > Is there anybody here who would like to tackle this?
> 
> After the roaring silence died down, I thought I should try myself.
> Here's my idea how to handfle that problem.  It's not even much code.
> 
> I would be really grateful if somebody (Chuck? Jason? Yaakov?) could have a 
> look if the idea is ok and maybe even test it.  With this code, the
> DLLs are tested if they allow writing at the time, and if not, are
> marked as not rebaseable.  If so, rebase will not try to move them,
> and they are kept in the database nevertheless.
> 
> 
> Corinna

I extended the patch a bit, so that it prints on the command line which
DLL couldn't be rebased for what reason.  See below.  Did anybody try
the patch except me?


Corinna


Index: rebase-db.h
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase-db.h,v
retrieving revision 1.3
diff -u -p -r1.3 rebase-db.h
--- rebase-db.h	5 Aug 2011 14:21:11 -0000	1.3
+++ rebase-db.h	13 Mar 2012 13:03:17 -0000
@@ -63,8 +63,10 @@ typedef struct _img_info
   ULONG   size;		/* Size of the DLL at rebased time.                  */
   ULONG   slot_size;	/* Size of the DLL rounded to allocation granularity.*/
   struct {		/* Flags                                             */
-    unsigned needs_rebasing : 1; /* Set to 0 in the database.  Used only     */
-				 /* while rebasing.                          */
+    ULONG needs_rebasing : 1; /* Set to 0 in the database.  Used only        */
+			      /* while rebasing.                             */
+    ULONG cannot_rebase  : 1; /* Set to 0 in the database.  Used only        */
+			      /* while rebasing.                             */
   } flag;
 } img_info_t;
 
Index: rebase.c
===================================================================
RCS file: /sourceware/projects/cygwin-apps-home/cvsfiles/rebase/rebase.c,v
retrieving revision 1.12
diff -u -p -r1.12 rebase.c
--- rebase.c	9 Aug 2011 09:32:47 -0000	1.12
+++ rebase.c	13 Mar 2012 13:03:17 -0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2002, 2003, 2004, 2008, 2011 Jason Tishler
+ * Copyright (c) 2001, 2002, 2003, 2004, 2008, 2011, 2012 Jason Tishler
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -232,6 +232,8 @@ main (int argc, char *argv[])
   else
     {
       /* Rebase with database support. */
+      BOOL header;
+
       merge_image_info ();
       status = TRUE;
       for (i = 0; i < img_info_size; ++i)
@@ -242,6 +244,29 @@ main (int argc, char *argv[])
 	    if (status)
 	      img_info_list[i].flag.needs_rebasing = 0;
 	  }
+      for (header = FALSE, i = 0; i < img_info_size; ++i)
+	if (img_info_list[i].flag.cannot_rebase)
+	  {
+	    if (!header)
+	      {
+		fputs ("\nThe following DLLs couldn't be rebased "
+		       "because they were in use:\n", stderr);
+		header = TRUE;
+	      }
+	    fprintf (stderr, "  %s\n", img_info_list[i].name);
+	    img_info_list[i].flag.cannot_rebase = 0;
+	  }
+      for (header = FALSE, i = 0; i < img_info_size; ++i)
+	if (img_info_list[i].flag.needs_rebasing)
+	  {
+	    if (!header)
+	      {
+		fputs ("\nThe following DLLs couldn't be rebased "
+		       "due to errors:\n", stderr);
+		header = TRUE;
+	      }
+	    fprintf (stderr, "  %s\n", img_info_list[i].name);
+	  }
       if (save_image_info () < 0)
 	return 2;
     }
@@ -269,8 +294,10 @@ save_image_info ()
   /* Remove all DLLs which couldn't be rebased from the list before storing
      it in the database file. */
   for (i = 0; i < img_info_size; ++i)
-    if (img_info_list[i].flag.needs_rebasing)
-      img_info_list[i--] = img_info_list[--img_info_size];
+    {
+      if (img_info_list[i].flag.needs_rebasing)
+	img_info_list[i--] = img_info_list[--img_info_size];
+    }
   /* Create a temporary file to write to. */
   fd = mkstemp (tmp_file);
   if (fd < 0)
@@ -509,6 +536,17 @@ load_image_info ()
   return ret;
 }
 
+static BOOL
+set_cannot_rebase (img_info_t *img)
+{
+  int fd = open (img->name, O_WRONLY);
+  if (fd < 0)
+    img->flag.cannot_rebase = 1;
+  else
+    close (fd);
+  return img->flag.cannot_rebase;
+}
+
 int
 merge_image_info ()
 {
@@ -541,6 +579,9 @@ merge_image_info ()
     {
       for (i = img_info_rebase_start; i < img_info_size; ++i)
 	{
+	  /* First test if we can open the DLL for writing.  If not, it's
+	     probably blocked by another process. */
+	  set_cannot_rebase (&img_info_list[i]);
 	  match = bsearch (&img_info_list[i], img_info_list,
 			   img_info_rebase_start, sizeof (img_info_t),
 			   img_info_name_cmp);
@@ -551,8 +592,10 @@ merge_image_info ()
 		 of the old file.  If so, screw the new file into the old slot.
 		 Otherwise set base to 0 to indicate that this DLL needs a new
 		 base address. */
-	      if (match->base != img_info_list[i].base
-		  || match->slot_size < img_info_list[i].slot_size)
+	      if (img_info_list[i].flag.cannot_rebase)
+		match->base = img_info_list[i].base;
+	      else if (match->base != img_info_list[i].base
+		       || match->slot_size < img_info_list[i].slot_size)
 		{
 		  /* Reuse the old address if possible. */
 		  if (match->slot_size < img_info_list[i].slot_size)
@@ -566,23 +609,24 @@ merge_image_info ()
 	      free (img_info_list[i].name);
 	      img_info_list[i--] = img_info_list[--img_info_size];
 	    }
-	  else
+	  else if (!img_info_list[i].flag.cannot_rebase)
 	    /* Not in database yet.  Set base to 0 to choose a new one. */
 	    img_info_list[i].base = 0;
 	}
-      /* After eliminating the duplicates, check if the user requested
-	 a new base address on the command line.  If so, overwrite all
-	 base addresses with 0 and set img_info_rebase_start to 0, to
-	 skip any further test. */
-      if (force_rebase_flag)
-	img_info_rebase_start = 0;
     }
-  if (!img_info_rebase_start)
+  if (!img_info_rebase_start || force_rebase_flag)
     {
       /* No database yet or enforcing a new base address.  Set base of all
-	 DLLs to 0. */
+	 DLLs to 0, if possible. */
       for (i = 0; i < img_info_size; ++i)
-	img_info_list[i].base = 0;
+	{
+	  /* Test DLLs already in database for writability. */
+	  if (i < img_info_rebase_start)
+	    set_cannot_rebase (&img_info_list[i]);
+	  if (!img_info_list[i].flag.cannot_rebase)
+	    img_info_list[i].base = 0;
+	}
+      img_info_rebase_start = 0;
     }
 
   /* Now sort the old part of the list by base address. */
@@ -596,8 +640,10 @@ merge_image_info ()
       ULONG64 cur_base;
       ULONG cur_size, slot_size;
 
-      /* Files with the needs_rebasing flag set have been checked already. */
-      if (img_info_list[i].flag.needs_rebasing)
+      /* Files with the needs_rebasing or cannot_rebase flags set have been
+	 checked already. */
+      if (img_info_list[i].flag.needs_rebasing
+      	  || img_info_list[i].flag.cannot_rebase)
 	continue;
       /* Check if the files in the old list still exist.  Drop non-existant
 	 or unaccessible files. */
@@ -613,24 +659,34 @@ merge_image_info ()
 	  continue;
 	}
       slot_size = roundup2 (cur_size, ALLOCATION_SLOT);
-      /* If the file has been reinstalled, try to rebase to the same address
-	 in the first place. */
-      if (cur_base != img_info_list[i].base)
+      if (set_cannot_rebase (&img_info_list[i]))
+	img_info_list[i].base = cur_base;
+      else
 	{
-	  img_info_list[i].flag.needs_rebasing = 1;
-	  /* Set cur_base to the old base to simplify subsequent tests. */
-	  cur_base = img_info_list[i].base;
+	  /* If the file has been reinstalled, try to rebase to the same address
+	     in the first place. */
+	  if (cur_base != img_info_list[i].base)
+	    {
+	      img_info_list[i].flag.needs_rebasing = 1;
+	      /* Set cur_base to the old base to simplify subsequent tests. */
+	      cur_base = img_info_list[i].base;
+	    }
+	  /* However, if the DLL got bigger and doesn't fit into its slot
+	     anymore, rebase this DLL from scratch. */
+	  if (i + 1 < img_info_rebase_start
+	      && cur_base + slot_size + offset >= img_info_list[i + 1].base)
+	    img_info_list[i].base = 0;
+	  /* Does the previous DLL reach into the address space of this
+	     DLL?  This happens if the previous DLL is not rebaseable. */
+	  else if (i > 0 && cur_base < img_info_list[i - 1].base
+				       + img_info_list[i + 1].slot_size)
+	    img_info_list[i].base = 0;
+	  /* Does the file match the base address requirements?  If not,
+	     rebase from scratch. */
+	  else if ((down_flag && cur_base + slot_size + offset >= image_base)
+		   || (!down_flag && cur_base < image_base))
+	    img_info_list[i].base = 0;
 	}
-      /* However, if the DLL got bigger and doesn't fit into its slot
-	 anymore, rebase this DLL from scratch. */
-      if (i + 1 < img_info_rebase_start
-	  && cur_base + slot_size + offset >= img_info_list[i + 1].base)
-	img_info_list[i].base = 0;
-      /* Does the file match the base address requirements?  If not,
-	 rebase from scratch. */
-      else if ((down_flag && cur_base + slot_size + offset >= image_base)
-	       || (!down_flag && cur_base < image_base))
-	img_info_list[i].base = 0;
       /* Unconditionally overwrite old with new size. */
       img_info_list[i].size = cur_size;
       img_info_list[i].slot_size = slot_size;

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat



More information about the Cygwin-apps mailing list