This is the mail archive of the libc-locales@sourceware.org mailing list for the GNU libc locales project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug localedata/12788] New: [PATCH] setlocale sets the locale ofLC_ALL incorrect to 'C' in some cases (/when LC_CTYPE is used)


http://sourceware.org/bugzilla/show_bug.cgi?id=12788

           Summary: [PATCH] setlocale sets the locale of LC_ALL incorrect
                    to 'C' in some cases (/when LC_CTYPE is used)
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: normal
          Priority: P2
         Component: localedata
        AssignedTo: libc-locales@sources.redhat.com
        ReportedBy: bug_rh@spam.wizbit.be


Created attachment 5739
  --> http://sourceware.org/bugzilla/attachment.cgi?id=5739
patch - update the condition in set_composite_name

There is a bug in setlocale that can result in LC_ALL being incorrectly set to
LC_ALL.

Test case:

$ cat bug-setlocale.c 
#include <stdio.h>
#include <locale.h>

int main () {
        printf("setlocale(LC_ALL, \"\") = %s\n", setlocale(LC_ALL, ""));
        printf("setlocale(LC_CTYPE, \"\") = %s\n", setlocale(LC_CTYPE, ""));
        printf("setlocale(LC_ALL, NULL) = %s\n", setlocale(LC_ALL, NULL));
        printf("setlocale(LC_NUMERIC, \"\") = %s\n", setlocale(LC_NUMERIC,
""));
        printf("setlocale(LC_ALL, NULL) = %s\n", setlocale(LC_ALL, NULL));

        setlocale(LC_ALL, "C"); 
        printf("setlocale(LC_ALL, NULL) = %s\n", setlocale(LC_ALL, NULL));
        printf("setlocale(LC_CTYPE, NULL) = %s\n", setlocale(LC_CTYPE, NULL));
}


Running it:

$ env -i LC_CTYPE=en_US ./bug-setlocale
setlocale(LC_ALL, "") = LC_CTYPE=en_US;LC_NUMERIC=C;LC_....  # => expected
setlocale(LC_CTYPE, "") = en_US                              # => expected
setlocale(LC_ALL, NULL) = LC_CTYPE=en_US;LC_NUMERIC=C;LC_... # => expected
setlocale(LC_NUMERIC, "") = C                                # => expected
setlocale(LC_ALL, NULL) = C                                  # => not expected;
expected value: LC_CTYPE=en_US;LC_NUMERIC=C;LC_...
setlocale(LC_ALL, NULL) = C                                  # => expected
setlocale(LC_CTYPE, NULL) = en_US                            # => not expected;
expected value: 'C'


Important when running the test case:
a) the locale en_US needs to be installed/needs to exists on the system
b) only the environment variable LC_CTYPE should be set (LC_ALL, LANG,
LC_COLLATE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME need to be unset)

I traced the problem to the file locale/setlocale.c, function:
new_composite_name, line: 150-160:

  for (i = 0; i < __LC_LAST; ++i)
    if (i != LC_ALL)
      {
        const char *name = (category == LC_ALL ? newnames[i] :
                            category == i ? newnames[0] :
                            _nl_global_locale.__names[i]);
        last_len = strlen (name);
        cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
        if (i > 0 && same && strcmp (name, newnames[0]) != 0)
          same = 0;
      }

The problem is the condition on line 158: the  'i > 0'  is incorrect.
The condition should be: ((category == LC_ALL && i > 0) || (category != LC_ALL
&& i != category))


The reasoning/the explanation (using the above test case):

A) setlocale(LC_ALL, ""):

This calls new_composite_name with category = 6 and newnames an array of 13
elements.
For i = 0: name = newnames[0]  => strcmp(name, newnames[0]) != 0  can be
skipped
For i = 1: name = newnames[1]  => strcmp(name, newnames[1]) != 0  can not be
skipped

B) setlocale(LC_CTYPE, "")

This calls new_composite_name with category = 0 and newnames an array of 1
element

For i = 0: name = newnames[0]  => strcmp(name, newnames[0]) != 0  can be
skipped
For i = 1: name = _nl_global_locale.__names[1]  => strcmp(name, newnames[0]) !=
0  can not be skipped


C) setlocale(LC_NUMERIC, "")

This calls new_composite_name with category = 1 and newnames an array of 1
element

For i = 0: name = _nl_global_locale.__names[0]  => strcmp(name, newnames[0]) !=
0  can not be skipped
For i = 1: name = newnames[0] => strcmp(name, newnames[0]) != 0  can be skipped



==> strcmp(name, newnames[0]) != 0 can only be skipped if:

* category == LC_ALL and i == 0
* category != LC_ALL and i == category



The bug was (I believe) introduced in commit
4b10dd6c1959577f57850ca427a94fe22b9f3299 (dated Tue, 31 Aug 1999 07:04:41 +0000
(07:04 +0000))


Attached is a patch which updates the condition.


The output after the patch:

$ env -i LC_CTYPE=en_US ./bug-setlocale
setlocale(LC_ALL, "") =
LC_CTYPE=en_US;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C
setlocale(LC_CTYPE, "") = en_US
setlocale(LC_ALL, NULL) =
LC_CTYPE=en_US;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C
setlocale(LC_NUMERIC, "") = C
setlocale(LC_ALL, NULL) =
LC_CTYPE=en_US;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C
setlocale(LC_ALL, NULL) = C
setlocale(LC_CTYPE, NULL) = C

-- 
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.


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