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]
Other format: [Raw text]

[PATCH] Fix newlocale, uselocale, duplocale, is*_l and to*_l


Hi!

The following patch fixes a bunch of things.

Primarily, addition of __names[] array to __locale_struct broke binary
compatibility - programs using e.g. isdigit_l etc. suddenly give
broken results (including libstdc++-v3).

Second, at least tllocale.ps documents uselocale:
> The function returns the locale handle previously passed
> to uselocale() for the current thread. If there was no such call
> before the return value is LC_GLOBAL_LOCALE.
That's also consistent with setlocale behaviour (and libstdc++-v3 uses it).
But current uselocale only returns previous locale if called with
uselocale(NULL) and otherwise returns the argument which was passed to it.
That would mean
locale_t old = uselocale(new);
something
uselocale(old);
sequence would have to be rewritten as:
locale_t old = uselocale(NULL);
uselocale(new);
something
uselocale(old);
I really thing we should follow the paper in here.

Third thing is uselocale and gettext - although __names was introduced,
newlocale created locales would have all __names[X] set to _nl_C_name
and thus gettext would not work properly.

The fourth thing is newlocale/duplocale failure handling and on success
avoiding memory leaking.

2002-08-31  Jakub Jelinek  <jakub@redhat.com>

	* locale/newlocale.c: Include string.h.
	(__newlocale): Fill in __names elements, free them on failure.
	On failure call _nl_remove_locale when necessary.
	Free old __names and all locale data if using base.
	* locale/duplocale.c (__duplocale): Free newly strduped __names,
	not members of dataset on failure.
	* locale/uselocale.c (__uselocale): Always return previous locale_t,
	not only when newloc is NULL.
	* locale/xlocale.h (__struct locale_struct): Put __names last
	for binary compatibility of inline is*_l and to*_l.

--- libc/locale/newlocale.c.jj	2002-08-12 15:27:48.000000000 +0200
+++ libc/locale/newlocale.c	2002-08-31 17:06:46.000000000 +0200
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <locale.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "localeinfo.h"
 
@@ -148,7 +149,32 @@ __newlocale (int category_mask, const ch
 	result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len,
 						 cnt, &newnames[cnt]);
 	if (result.__locales[cnt] == NULL)
-	  return NULL;
+	  {
+ exit_free:
+	    for (--cnt; cnt >= 0; --cnt)
+	      if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0)
+		{
+		  if (result.__locales[cnt]->usage_count != UNDELETABLE)
+		    /* We can remove the data.  */
+		    _nl_remove_locale (cnt, result.__locales[cnt]);
+		  if (result.__names[cnt] != _nl_C_name)
+		    free ((char *) result.__names[cnt]);
+		}
+	    return NULL;
+	  }
+	if (newnames[cnt] == _nl_C_name)
+	  result.__names[cnt] = _nl_C_name;
+	else
+	  {
+	    result.__names[cnt] = __strdup (newnames[cnt]);
+	    if (result.__names[cnt] == NULL)
+	      {
+		if (result.__locales[cnt]->usage_count != UNDELETABLE)
+		  /* We can remove the data.  */
+		  _nl_remove_locale (cnt, result.__locales[cnt]);
+		goto exit_free;
+	      }
+	  }
       }
 
   /* We successfully loaded all required data.  */
@@ -157,12 +183,24 @@ __newlocale (int category_mask, const ch
       /* Allocate new structure.  */
       result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
       if (result_ptr == NULL)
-	return NULL;
-
+	goto exit_free;
     }
   else
-    /* We modify the base structure.  */
-    result_ptr = base;
+    {
+      /* We modify the base structure.  */
+      result_ptr = base;
+
+      /* Need to free the old names and old locale data.  */
+      for (cnt = 0; cnt < __LC_LAST; ++cnt)
+	if (cnt != LC_ALL && (category_mask & 1 << cnt) != 0)
+	  {
+	    if (base->__locales[cnt]->usage_count != UNDELETABLE)
+	      /* We can remove the data.  */
+	      _nl_remove_locale (cnt, base->__locales[cnt]);
+	    if (base->__names[cnt] != _nl_C_name)
+	      free ((char *) base->__names[cnt]);
+	  }
+    }
 
   *result_ptr = result;
 
--- libc/locale/duplocale.c.jj	2002-08-31 09:40:42.000000000 +0200
+++ libc/locale/duplocale.c	2002-08-31 17:06:46.000000000 +0200
@@ -55,9 +55,9 @@ __duplocale (__locale_t dataset)
 	      result->__names[cnt] = __strdup (dataset->__names[cnt]);
 	      if (result->__names[cnt] == NULL)
 		{
-		  while (cnt-- > 0)
-		    if (dataset->__names[cnt] != _nl_C_name)
-		      free ((char *) dataset->__names[cnt]);
+		  while (--cnt >= 0)
+		    if (result->__names[cnt] != _nl_C_name)
+		      free ((char *) result->__names[cnt]);
 		  free (result);
 		  result = NULL;
 		  break;
--- libc/locale/uselocale.c.jj	2002-08-28 12:58:05.000000000 +0200
+++ libc/locale/uselocale.c	2002-08-31 18:07:09.000000000 +0200
@@ -28,16 +28,16 @@
 locale_t
 __uselocale (locale_t newloc)
 {
-  if (newloc == NULL)
-    {
-      locale_t loc = __libc_tsd_get (LOCALE);
-      return loc == &_nl_global_locale ? LC_GLOBAL_LOCALE : loc;
-    }
-  else
+  locale_t oldloc = __libc_tsd_get (LOCALE);
+
+  if (oldloc == &_nl_global_locale)
+    oldloc = LC_GLOBAL_LOCALE;
+
+  if (newloc != NULL)
     {
-      const locale_t locobj
-	= newloc == LC_GLOBAL_LOCALE ? &_nl_global_locale : newloc;
-      __libc_tsd_set (LOCALE, locobj);
+      if (newloc == LC_GLOBAL_LOCALE)
+	newloc = &_nl_global_locale;
+      __libc_tsd_set (LOCALE, newloc);
 
 #ifdef NL_CURRENT_INDIRECT
       /* Now we must update all the per-category thread-local variables to
@@ -58,13 +58,13 @@ __uselocale (locale_t newloc)
 	weak_extern (_nl_current_##category##_used)			      \
 	weak_extern (_nl_current_##category)				      \
 	if (&_nl_current_##category##_used != 0)			      \
-	  _nl_current_##category = &locobj->__locales[category];	      \
+	  _nl_current_##category = &newloc->__locales[category];	      \
       }
 # include "categories.def"
 # undef	DEFINE_CATEGORY
 #endif
     }
 
-  return newloc;
+  return oldloc;
 }
 weak_alias (__uselocale, uselocale)
--- libc/locale/xlocale.h.jj	2002-08-31 09:40:42.000000000 +0200
+++ libc/locale/xlocale.h	2002-08-31 19:40:35.000000000 +0200
@@ -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]; /* 13 = __LC_LAST. */
 } *__locale_t;
 
 #endif /* xlocale.h */

	Jakub


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