This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Properly handle systems with crippled locales
authorKarl Williamson <khw@cpan.org>
Mon, 4 Mar 2019 19:27:59 +0000 (12:27 -0700)
committerKarl Williamson <khw@cpan.org>
Mon, 4 Mar 2019 20:01:37 +0000 (13:01 -0700)
Some systems fake their locales, so that they pretend to accept a locale
change, but they either do nothing, making everything the C locale, or
on some systems there is a a second locale "C-UTF-8" that can be
switched to.  Configure probes have been added to find such systems, and
this commit changes to use the results of these probes, so that we don't
try looking for other locales (any names we came up with would be
accepted as valid, but don't work, and tests were failing as a result).

Anything running the musl library fits, as does OpenBSD and its kin, as
they view locales as security risks.  This commit allows us to take out
some code that was looking for particular OS's.

lib/locale.t
locale.c
t/loc_tools.pl
t/run/locale.t

index 0f43dff..4c324ea 100644 (file)
@@ -2543,7 +2543,7 @@ foreach $test_num ($first_locales_test_number..$final_locales_test_number) {
 
 $test_num = $final_locales_test_number;
 
-unless ( $os =~ m!^(dragonfly|openbsd|bitrig|mirbsd)$! ) {
+if ( ! defined $Config{d_setlocale_accepts_any_locale_name}) {
     # perl #115808
     use warnings;
     my $warned = 0;
index e2bb54e..2b123d1 100644 (file)
--- a/locale.c
+++ b/locale.c
@@ -589,8 +589,11 @@ S_emulate_setlocale(const int category,
         /* If this assert fails, adjust the size of curlocales in intrpvar.h */
         STATIC_ASSERT_STMT(C_ARRAY_LENGTH(PL_curlocales) > LC_ALL_INDEX);
 
-#    if defined(_NL_LOCALE_NAME) && defined(DEBUGGING)
-
+#    if   defined(_NL_LOCALE_NAME)                      \
+     &&   defined(DEBUGGING)                            \
+     && ! defined(SETLOCALE_ACCEPTS_ANY_LOCALE_NAME)
+          /* On systems that accept any locale name, the real underlying locale
+           * is often returned by this internal function, so we can't use it */
         {
             /* Internal glibc for querylocale(), but doesn't handle
              * empty-string ("") locale properly; who knows what other
index f8edaad..310eb2c 100644 (file)
@@ -109,21 +109,14 @@ sub _trylocale ($$$$) { # For use only by other functions in this file!
     # systems
     return if $locale =~ / ^ pig $ /ix;
 
-    # As of 6.3, this platform's locale handling is basically broken.  khw
-    # filed a bug report (no ticket number was returned), and it is supposedly
-    # going to change in a future release, so the statements here below sunset
-    # for any larger version, at which point this may start failing and have
-    # to be revisited.
-    #
-    # Given a legal individual category, basically whatever you set the locale
-    # to, the return from setlocale() indicates that it has taken effect, even
-    # if it hasn't.  However, the return from querying LC_ALL won't reflect
-    # this.
-    if ($Config{osname} =~ /openbsd/i && $locale !~ / ^ (?: C | POSIX ) $/ix) {
-        my ($major, $minor) = $Config{osvers} =~ / ^ ( \d+ ) \. ( \d+ ) /ax;
-        return if ! defined $major || ! defined $minor
-                         || $major < 6 || ($major == 6 && $minor <= 3);
-    }
+    # Certain platforms have a crippled locale system in which setlocale
+    # returns success for just about any possible locale name, but if anything
+    # actually happens as a result of the call, it is that the underlying
+    # locale is set to a system default, likely C or C.UTF-8.  We can't test
+    # such systems fully, but we shouldn't disable the user from using
+    # locales, as it may work out for them (or not).
+    return if    defined $Config{d_setlocale_accepts_any_locale_name}
+              && $locale !~ / ^ (?: C | POSIX | C\.UTF-8 ) $/ix;
 
     $categories = [ $categories ] unless ref $categories;
 
@@ -342,6 +335,10 @@ sub find_locales ($;$) {
         _trylocale("C.UTF-8", $categories, \@Locale, $allow_incompatible);
     }
 
+    # There's no point in looking at anything more if we know that setlocale
+    # will return success on any garbage or non-garbage name.
+    return sort @Locale if defined $Config{d_setlocale_accepts_any_locale_name};
+
     foreach (1..16) {
         _trylocale("ISO8859-$_", $categories, \@Locale, $allow_incompatible);
         _trylocale("iso8859$_", $categories, \@Locale, $allow_incompatible);
index 0296c9a..78cfc2f 100644 (file)
@@ -68,7 +68,7 @@ EOF
 
 my $non_C_locale;
 foreach my $locale (@locales) {
-    next if $locale eq "C" || $locale eq 'POSIX';
+    next if $locale eq "C" || $locale eq 'POSIX' || $locale eq "C.UTF-8";
     $non_C_locale = $locale;
     last;
 }
@@ -460,15 +460,15 @@ EOF
     }
 
 SKIP: {
-        # Note: a Configure probe could be written to give us the syntax to
-        # use, but khw doesn't think it's worth it.  If the POSIX 2008 locale
-        # functions are being used, the syntax becomes mostly irrelevant, so
-        # do the test anyway if they are
-        # it's a lot of trouble to figure out in a perl script
-        if ($^O eq 'openbsd' && (     $Config{useithreads} ne 'define'
-                                 || ! ${^SAFE_LOCALES}))
+        # Note: the setlocale Configure probe could be enhanced to give us the
+        # syntax to use, but khw doesn't think it's worth it at this time, as
+        # the current outliers seem to be skipped by the test just below
+        # anyway.  If the POSIX 2008 locale functions are being used, the
+        # syntax becomes mostly irrelevant, so do the test anyway if they are.
+        # It's a lot of trouble to figure out in a perl script.
+        if ($Config{d_setlocale_accepts_any_locale_name} eq 'true')
         {
-            skip("The setlocale() syntax used is invalid on this platform", 2);
+            skip("Can't distinguish between valid and invalid locale names on this system", 2);
         }
 
         my @valid_categories = valid_locale_categories();