* locale/newlocale.c (__newlocale): Don't use strdup for names.
authorRoland McGrath <roland@gnu.org>
Sat, 31 Aug 2002 20:08:18 +0000 (20:08 +0000)
committerRoland McGrath <roland@gnu.org>
Sat, 31 Aug 2002 20:08:18 +0000 (20:08 +0000)
Instead, make the single allocation of the structure larger to hold
the name strings.
* locale/duplocale.c (__duplocale): Don't strdup names individually.
Instead, calculate size for a single allocation and copy into it.
* locale/freelocale.c (__freelocale): Don't free names individually.

ChangeLog
locale/duplocale.c
locale/freelocale.c
locale/newlocale.c
locale/xlocale.h

index a6228d2..5c72fa4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2002-08-31  Roland McGrath  <roland@redhat.com>
 
+       * locale/newlocale.c (__newlocale): Don't use strdup for names.
+       Instead, make the single allocation of the structure larger to hold
+       the name strings.
+       * locale/duplocale.c (__duplocale): Don't strdup names individually.
+       Instead, calculate size for a single allocation and copy into it.
+       * locale/freelocale.c (__freelocale): Don't free names individually.
+
        * locale/newlocale.c (__newlocale): Don't leak old data or names.
 
        * locale/xlocale.h (__locale_struct): Move __names member last,
index 867232e..2fa29d1 100644 (file)
@@ -35,54 +35,47 @@ __duplocale (__locale_t dataset)
 {
   __locale_t result;
   int cnt;
+  size_t names_len = 0;
 
-  /* We modify global data.  */
-  __libc_lock_lock (__libc_setlocale_lock);
+  /* Calculate the total space we need to store all the names.  */
+  for (cnt = 0; cnt < __LC_LAST; ++cnt)
+    if (cnt != LC_ALL && dataset->__names[cnt] != _nl_C_name)
+      names_len += strlen (dataset->__names[cnt]) + 1;
 
   /* Get memory.  */
-  result = (__locale_t) malloc (sizeof (struct __locale_struct));
-
-  if (result != NULL)
-    /* Duplicate the names in a separate loop first so we can
-       bail out if strdup fails and not have touched usage_counts.  */
-    for (cnt = 0; cnt < __LC_LAST; ++cnt)
-      if (cnt != LC_ALL)
-       {
-         if (dataset->__names[cnt] == _nl_C_name)
-           result->__names[cnt] = _nl_C_name;
-         else
-           {
-             result->__names[cnt] = __strdup (dataset->__names[cnt]);
-             if (result->__names[cnt] == NULL)
-               {
-                 while (cnt-- > 0)
-                   if (result->__names[cnt] != _nl_C_name)
-                     free ((char *) result->__names[cnt]);
-                 free (result);
-                 result = NULL;
-                 break;
-               }
-           }
-       }
+  result = malloc (sizeof (struct __locale_struct) + names_len);
 
   if (result != NULL)
     {
+      char *namep = (char *) (result + 1);
+
+      /* We modify global data (the usage counts).  */
+      __libc_lock_lock (__libc_setlocale_lock);
+
       for (cnt = 0; cnt < __LC_LAST; ++cnt)
        if (cnt != LC_ALL)
          {
            result->__locales[cnt] = dataset->__locales[cnt];
            if (result->__locales[cnt]->usage_count < MAX_USAGE_COUNT)
              ++result->__locales[cnt]->usage_count;
+
+           if (dataset->__names[cnt] == _nl_C_name)
+             result->__names[cnt] = _nl_C_name;
+           else
+             {
+               result->__names[cnt] = namep;
+               namep = __stpcpy (namep, dataset->__names[cnt]) + 1;
+             }
          }
 
       /* Update the special members.  */
       result->__ctype_b = dataset->__ctype_b;
       result->__ctype_tolower = dataset->__ctype_tolower;
       result->__ctype_toupper = dataset->__ctype_toupper;
-    }
 
-  /* It's done.  */
-  __libc_lock_unlock (__libc_setlocale_lock);
+      /* It's done.  */
+      __libc_lock_unlock (__libc_setlocale_lock);
+    }
 
   return result;
 }
index 2ba1432..ba0ae85 100644 (file)
@@ -34,23 +34,18 @@ __freelocale (__locale_t dataset)
 {
   int cnt;
 
-  /* We modify global data.  */
+  /* We modify global data (the usage counts).  */
   __libc_lock_lock (__libc_setlocale_lock);
 
   for (cnt = 0; cnt < __LC_LAST; ++cnt)
-    if (cnt != LC_ALL)
-      {
-       if (dataset->__locales[cnt]->usage_count != UNDELETABLE)
-         /* We can remove the data.  */
-         _nl_remove_locale (cnt, dataset->__locales[cnt]);
-       if (dataset->__names[cnt] != _nl_C_name)
-         free ((char *) dataset->__names[cnt]);
-      }
-
-  /* Free the locale_t handle itself.  */
-  free (dataset);
+    if (cnt != LC_ALL && dataset->__locales[cnt]->usage_count != UNDELETABLE)
+      /* We can remove the data.  */
+      _nl_remove_locale (cnt, dataset->__locales[cnt]);
 
   /* It's done.  */
   __libc_lock_unlock (__libc_setlocale_lock);
+
+  /* Free the locale_t handle itself.  */
+  free (dataset);
 }
 weak_alias (__freelocale, freelocale)
index ef6f94b..3b8676c 100644 (file)
@@ -46,6 +46,7 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
   size_t locale_path_len;
   const char *locpath_var;
   int cnt;
+  size_t names_len;
 
   /* We treat LC_ALL in the same way as if all bits were set.  */
   if (category_mask == 1 << LC_ALL)
@@ -143,83 +144,98 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
     }
 
   /* Now process all categories we are interested in.  */
+  names_len = 0;
   for (cnt = 0; cnt < __LC_LAST; ++cnt)
-    if ((category_mask & 1 << cnt) != 0)
-      {
-       result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len,
-                                                cnt, &newnames[cnt]);
-       if (result.__locales[cnt] == NULL)
-         {
-         free_data_and_exit:
-           while (cnt-- > 0)
-             if (((category_mask & 1 << cnt) != 0)
-                 && result.__locales[cnt]->usage_count != UNDELETABLE)
-               /* We can remove the data.  */
-               _nl_remove_locale (cnt, result.__locales[cnt]);
-           return NULL;
-         }
-      }
+    {
+      if ((category_mask & 1 << cnt) != 0)
+       {
+         result.__locales[cnt] = _nl_find_locale (locale_path,
+                                                  locale_path_len,
+                                                  cnt, &newnames[cnt]);
+         if (result.__locales[cnt] == NULL)
+           {
+           free_cnt_data_and_exit:
+             while (cnt-- > 0)
+               if (((category_mask & 1 << cnt) != 0)
+                   && result.__locales[cnt]->usage_count != UNDELETABLE)
+                 /* We can remove the data.  */
+                 _nl_remove_locale (cnt, result.__locales[cnt]);
+             return NULL;
+           }
+
+         if (newnames[cnt] != _nl_C_name)
+           names_len += strlen (newnames[cnt]) + 1;
+       }
+      else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
+       /* Tally up the unchanged names from BASE as well.  */
+       names_len += strlen (result.__names[cnt]) + 1;
+    }
+
+  /* We successfully loaded all required data.  Allocate a new structure.
+     We can't just reuse the BASE pointer, because the name strings are
+     changing and we need the old name string area intact so we can copy
+     out of it into the new one without overlap problems should some
+     category's name be getting longer.  */
+  result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
+  if (result_ptr == NULL)
+    {
+      cnt = __LC_LAST;
+      goto free_cnt_data_and_exit;
+    }
 
-  /* We successfully loaded all required data.  */
   if (base == NULL)
     {
-      /* Allocate new structure.  */
-      result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
-      if (result_ptr == NULL)
-       goto free_data_and_exit;
+      /* Fill in this new structure from scratch.  */
+
+      char *namep = (char *) (result_ptr + 1);
 
-      /* Install strdup'd names in the new structure's __names array.
+      /* Install copied new names in the new structure's __names array.
         If resolved to "C", that is already in RESULT.__names to start.  */
       for (cnt = 0; cnt < __LC_LAST; ++cnt)
        if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
          {
-           result.__names[cnt] = __strdup (newnames[cnt]);
-           if (result.__names[cnt] == NULL)
-             {
-               free (result_ptr);
-               while (cnt-- > 0)
-                 if (result.__names[cnt] != _nl_C_name)
-                   free ((char *) result.__names[cnt]);
-               goto free_data_and_exit;
-             }
+           result.__names[cnt] = namep;
+           namep = __stpcpy (namep, newnames[cnt]) + 1;
          }
 
       *result_ptr = result;
     }
   else
     {
-      /* We modify the base structure.
-         First strdup the names we were given for the new locale.  */
+      /* We modify the base structure.  */
 
-      for (cnt = 0; cnt < __LC_LAST; ++cnt)
-       if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
-         {
-           newnames[cnt] = __strdup (newnames[cnt]);
-           if (newnames[cnt] == NULL)
-             {
-               while (cnt-- > 0)
-                 if ((category_mask & 1 << cnt) != 0 &&
-                     newnames[cnt] != _nl_C_name)
-                   free ((char *) newnames[cnt]);
-               goto free_data_and_exit;
-             }
-         }
+      char *namep = (char *) (result_ptr + 1);
 
-      /* Now that we can't lose, install the new data.  */
       for (cnt = 0; cnt < __LC_LAST; ++cnt)
        if ((category_mask & 1 << cnt) != 0)
          {
            if (base->__locales[cnt]->usage_count != UNDELETABLE)
              /* We can remove the old data.  */
              _nl_remove_locale (cnt, base->__locales[cnt]);
-           base->__locales[cnt] = result.__locales[cnt];
+           result_ptr->__locales[cnt] = result.__locales[cnt];
 
-           if (base->__names[cnt] != _nl_C_name)
-             free ((char *) base->__names[cnt]);
-           base->__names[cnt] = newnames[cnt];
+           if (newnames[cnt] == _nl_C_name)
+             result_ptr->__names[cnt] = _nl_C_name;
+           else
+             {
+               result_ptr->__names[cnt] = namep;
+               namep = __stpcpy (namep, newnames[cnt]) + 1;
+             }
+         }
+       else if (cnt != LC_ALL)
+         {
+           /* The RESULT members point into the old BASE structure.  */
+           result_ptr->__locales[cnt] = result.__locales[cnt];
+           if (result.__names[cnt] == _nl_C_name)
+             result_ptr->__names[cnt] = _nl_C_name;
+           else
+             {
+               result_ptr->__names[cnt] = namep;
+               namep = __stpcpy (namep, result.__names[cnt]) + 1;
+             }
          }
 
-      result_ptr = base;
+      free (base);
     }
 
   /* Update the special members.  */
index 4fb557d..2b17d69 100644 (file)
@@ -29,12 +29,14 @@ typedef struct __locale_struct
 {
   /* Note: LC_ALL is not a valid index into this array.  */
   struct locale_data *__locales[13]; /* 13 = __LC_LAST. */
-  const char *__names[13];
 
   /* To increase the speed of this solution we add some special members.  */
   const unsigned short int *__ctype_b;
   const int *__ctype_tolower;
   const int *__ctype_toupper;
+
+  /* Note: LC_ALL is not a valid index into this array.  */
+  const char *__names[13];
 } *__locale_t;
 
 #endif /* xlocale.h */