Skip to content

Commit

Permalink
S_find_locale_from_environment: Handle disparate LC_ALL
Browse files Browse the repository at this point in the history
Prior to this commit, it was possible on some platforms to improperly
set a locale category from a locale of "".

Consider:

export LC_ALL="LC_CTYPE=de_DE;LC_NUMERIC=C;LC_TIME=de_DE;..."

and then run

    print POSIX::setlocale(LC_NUMERIC, "");

It wouldn't know how to extract just the LC_NUMERIC part of the LC_ALL
string.

There is no test added because I didn't find a shell that allows setting
LC_ALL to such a disparate value.
  • Loading branch information
khwilliamson committed Nov 22, 2023
1 parent a6dd7c3 commit 89060ea
Showing 1 changed file with 36 additions and 1 deletion.
37 changes: 36 additions & 1 deletion locale.c
Expand Up @@ -3123,7 +3123,42 @@ S_find_locale_from_environment(pTHX_ const locale_category_index index)
/* Use any "LC_ALL" environment variable, as it overrides everything else.
* */
if (lc_all && strNE(lc_all, "")) {
return lc_all;
if (index == LC_ALL_INDEX_) {
return lc_all;
}

/* There is an LC_ALL environment variable, but we want only one
* component of it. Split the result into its individual components */
switch (parse_LC_ALL_string(lc_all,
(const char **) &locale_names,
no_override, /* Handled by other code */
false, /* Return only [0] if suffices */
false, /* Don't panic on error */
__LINE__))
{
case invalid:
return NULL;

case no_array:
return lc_all;

case only_element_0:
SAVEFREEPV(locale_names[0]);
return locale_names[0];

case full_array:
/* We need to mortalize the desired component, and free the rest */
for (unsigned int i = 0; i < LC_ALL_INDEX_; i++) {
if (i == index) {
SAVEFREEPV(locale_names[i]);
}
else {
Safefree(locale_names[i]);
}
}

return locale_names[index];
}
}

/* Here, no usable LC_ALL environment variable. We have to handle each
Expand Down

0 comments on commit 89060ea

Please sign in to comment.