This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix for localalias.c bug


Hi!

Below are two possible solutions for a pretty old bug in localealias.c which
is visible under ElectricFence:
If the string_space pool is too small, it is realloced, but realloc does not
guarantee it will return the same pointer as was passed to it, but we
already stored many string pointers to the old pool into the map array.
One fix I see is (assuming realloc usually will give the same address as
seems is the case in the common usage of setlocale in glibc, otherwise this
bug would have been noticed far before) in P2, basically we check if the
address changed and in the unlikely case that it changed we adjust the so
far created map[] entries.
The other fix is killing the realloc and replacing it with malloc - the
string pool does not have to be contiguous. I keep a linked list in the
first sizeof(char *) bytes of string pools so that they can be freed by
free_mem. This has the disadvantage of slightly higher overhead if realloc
would give the same address (at least because now we have to call free more
times) but big advantage if it would not (as there is no realloc, it does
not have to copy those thousands of bytes again and again, plus we don't
have to fix map[] entries).
Neither of these was tested, if you pick one solution you like, I'll test it
out.

	Jakub
2000-10-10  Jakub Jelinek  <jakub@redhat.com>

	* intl/localealias.c (read_alias_file): Don't realloc string_space,
	instead build a chain of string spaces.
	(free_mem): And free them as chain as well.

--- libc/intl/localealias.c.jj	Mon May  8 14:30:44 2000
+++ libc/intl/localealias.c	Tue Oct 10 23:00:55 2000
@@ -342,17 +342,19 @@ read_alias_file (fname, fname_len)
 	      if (string_space_act + alias_len + value_len > string_space_max)
 		{
 		  /* Increase size of memory pool.  */
-		  size_t new_size = (string_space_max
-				     + (alias_len + value_len > 1024
-					? alias_len + value_len : 1024));
-		  char *new_pool = (char *) realloc (string_space, new_size);
+		  size_t size = (alias_len + value_len + sizeof (char *) > 1024
+				 ? alias_len + value_len + sizeof (char *)
+				 : 1024));
+		  char *new_pool = (char *) malloc (size);
 		  if (new_pool == NULL)
 		    {
 		      FREE_BLOCKS (block_list);
 		      return added;
 		    }
+		  *(char **) new_pool = string_space;
+		  string_space_act = sizeof (char *);
 		  string_space = new_pool;
-		  string_space_max = new_size;
+		  string_space_max = size;
 		}
 
 	      map[nmap].alias = memcpy (&string_space[string_space_act],
@@ -405,8 +407,12 @@ extend_alias_table ()
 static void __attribute__ ((unused))
 free_mem (void)
 {
-  if (string_space != NULL)
-    free (string_space);
+  while (string_space)
+    {
+      char *next = *(char **) string_space;
+      free (string_space);
+      string_space = next;
+    }
   if (map != NULL)
     free (map);
 }
2000-10-10  Jakub Jelinek  <jakub@redhat.com>

	* intl/localalias.c (read_alias_file): If realloc returned a
	different address than was passed to it, adjust map array's string
	pointers.

--- libc/intl/localealias.c.jj	Mon May  8 14:30:44 2000
+++ libc/intl/localealias.c	Tue Oct 10 22:47:39 2000
@@ -351,6 +351,18 @@ read_alias_file (fname, fname_len)
 		      FREE_BLOCKS (block_list);
 		      return added;
 		    }
+
+		  if (string_space != new_pool)
+		    {
+		      size_t i;
+
+		      for (i = 0; i < nmap; i++)
+			{
+			  map[i].alias += new_pool - string_space;
+			  map[i].value += new_pool - string_space;
+			}
+		    }
+
 		  string_space = new_pool;
 		  string_space_max = new_size;
 		}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]