[PATCH] Fix setlocale bug
Jakub Jelinek
jakub@redhat.com
Thu Nov 30 05:39:00 GMT 2000
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
More information about the Libc-hacker
mailing list