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 setlocale bug


Hi!

Current setlocale implementation only stores copy of user provided string if
it is setting LC_ALL, otherwise it would store into _nl_current_names
second argument of setlocale directly (unless it was converted into _nl_C_name).
But user is allowed to do anything with that pointer after return from
setlocale, including freeing it, so we must make a copy.
Example of code which is fixed by this patch:
#include <locale.h>
#include <string.h>

int main()
{
  char q[10];
  setlocale(LC_ALL, "");
  strcpy(q, "de_DE");
  setlocale(LC_NUMERIC, q);
  strcpy(q, "xx_XX");
  printf ("%s\n", setlocale(LC_NUMERIC, NULL));
  exit (0);
}

Without this patch it prints xx_XX while with this patch it correctly prints
de_DE.

2000-11-30  Jakub Jelinek  <jakub@redhat.com>

	* setlocale.c (setname): Free for all categories, not just LC_ALL.
	(setlocale): Store a copy of string passed by user, not the string
	itself.

--- libc/setlocale.c.jj	Mon Nov 20 13:48:11 2000
+++ libc/setlocale.c	Thu Nov 30 13:57:06 2000
@@ -194,7 +194,7 @@ setname (int category, const char *name)
   if (_nl_current_names[category] == name)
     return;
 
-  if (category == LC_ALL && _nl_current_names[category] != _nl_C_name)
+  if (_nl_current_names[category] != _nl_C_name)
     free ((char *) _nl_current_names[category]);
 
   _nl_current_names[category] = name;
@@ -322,6 +322,14 @@ setlocale (int category, const char *loc
 	       control over the usage.  So we mark it as un-deletable.  */
 	    if (newdata[category]->usage_count != UNDELETABLE)
 	      newdata[category]->usage_count = UNDELETABLE;
+
+	    /* Make a copy of locale name.  */
+	    if (newnames[category] != _nl_C_name)
+	      {
+		newnames[category] = strdup (newnames[category]);
+		if (newnames[category] == NULL)
+		  break;
+	      }
 	  }
 
       /* Create new composite name.  */
@@ -342,6 +350,10 @@ setlocale (int category, const char *loc
 	     functions know about this.  */
 	  ++_nl_msg_cat_cntr;
 	}
+      else
+	for (++category; category < __LC_LAST; ++category)
+	  if (category != LC_ALL && newnames[category] != _nl_C_name)
+	    free ((char *) newnames[category]);
 
       /* Critical section left.  */
       __libc_lock_unlock (__libc_setlocale_lock);
@@ -376,10 +388,21 @@ setlocale (int category, const char *loc
 	    newdata->usage_count = UNDELETABLE;
 	}
 
+      /* Make a copy of locale name.  */
+      if (newname[0] != _nl_C_name)
+	{
+	  newname[0] = strdup (newname[0]);
+	  if (newname[0] == NULL)
+	    goto abort_single;
+	}
+
       /* Create new composite name.  */
       composite = new_composite_name (category, newname);
       if (composite == NULL)
 	{
+	  if (newname[0] != _nl_C_name)
+	    free ((char *) newname[0]);
+
 	  /* Say that we don't have any data loaded.  */
 	abort_single:
 	  newname[0] = NULL;

	Jakub

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