Skip to content

Commit

Permalink
Fix locale initialization bug
Browse files Browse the repository at this point in the history
On systems that have POSIX 2008 locales and haven't implemented a means
to find out what the current locale is, perl emulates this capability,
as best it can.

(Not having this capability is a defect in the POSIX standard, which has
been finally remedied in POSIX 2024

https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/getlocalename_l.html

but it will take time for implementations to catch up.)

In the absence of guidance from the Standard, some vendors created such
a means of getting this information, typically through a libc call named
'querylocale()'.

Perl uses whatever means is available and not buggy.  (Unfortunately
there are bugs or glitches in many of the implementations, so perl
doesn't use those.)

But when it doesn't have a useful means to get this information, perl
implements an emulation of it.  This works by perl trying to intercept
all changes to the locale and storing the new value, so that the
querylocale() emulation can simply return that when asked.

To save cycles, when asked to change the locale, perl skips actually
doing the change if it thinks it would be a no-op, that the new value is
the same as the old value.

Perl starts off setting itself to use the C locale and then reads the
environment to switch to what that specifies.

This bug here is that perl failed to tell the querylocale emulation at
the start that it was really in the C locale.  Due to the way initialization
proceeds, the querylocale emulation thought that perl was already in the
locale specified by the environment, so the code that changes the locale
skipped any changes.

This commit merely initializes the querylocale emulation records to C.
That way, if the environment specifies a different locale, perl knows it
isn't a no-op and does the change.

On glibc systems, there is a (mostly undocumented) means of finding the
current locale that turns out to work well.  Perl can use this.  In 5.38
we didn't know that it was reliable, given its undocumented status, so
it was by default turned off.  In 5.40, it is by default on.  This bug
does not come up if it is enabled.  To enable, call Configure adding the
option -Accflags=-DUSE_NL_LOCALE_NAME

(cherry picked from commit ecd3fa8)
  • Loading branch information
khwilliamson authored and steve-m-hay committed Jan 5, 2025
1 parent cc61c7c commit 5153d4d
Showing 1 changed file with 10 additions and 0 deletions.
10 changes: 10 additions & 0 deletions locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -5301,6 +5301,16 @@ Perl_init_i18nl10n(pTHX_ int printwarn)
* malloc'd in the interim */
uselocale(PL_C_locale_obj);

# ifdef USE_PL_CURLOCALES

/* Tell our querylocale emulation that we are in the C locale */
for (i = 0; i < NOMINAL_LC_ALL_INDEX; i++) {
(void) emulate_setlocale_i(i, "C",
RECALCULATE_LC_ALL_ON_FINAL_INTERATION,
__LINE__);
}

# endif
# ifdef USE_LOCALE_NUMERIC

PL_underlying_numeric_obj = duplocale(PL_C_locale_obj);
Expand Down

0 comments on commit 5153d4d

Please sign in to comment.