33e04c0
From 45cef8fb80248a6318f90219499ff2dbd953ae8c Mon Sep 17 00:00:00 2001
33e04c0
From: Karl Williamson <khw@cpan.org>
33e04c0
Date: Wed, 27 Nov 2019 19:15:11 -0700
33e04c0
Subject: [PATCH] PATCH: GH #17081: Workaround glibc bug with LC_MESSAGES
33e04c0
MIME-Version: 1.0
33e04c0
Content-Type: text/plain; charset=UTF-8
33e04c0
Content-Transfer-Encoding: 8bit
33e04c0
33e04c0
Please see the ticket for a full explanation.  This bug has been
33e04c0
submitted to glibc, without any real action forthcoming so far.
33e04c0
33e04c0
This invalidates the message cache each time the locale of LC_MESSAGES
33e04c0
is changed, as glibc should be doing this when uselocale changes that,
33e04c0
but glibc fails to do so.
33e04c0
33e04c0
This patch is an extension to the one submitted by Niko Tyni++.
33e04c0
33e04c0
I don't know how to test it, since a test would rely on several
33e04c0
different locales in different languages being available, and that
33e04c0
depends on what's installed on the platform.  I suppose that one could
33e04c0
go through the available locales, and try to find three with different
33e04c0
wording for the same message.  Doing so however would trigger the bug,
33e04c0
and at the end, if we didn't get three that differed, we wouldn't know
33e04c0
we wouldn't know if it is because of the bug, or that they just didn't
33e04c0
exist on the system.
33e04c0
33e04c0
However, below is a perl program that demonstrated the patch worked.
33e04c0
You could adjust it to the available locales.  The buggy code shows the
33e04c0
same text for all locales.  The fixed shows three different languages.
33e04c0
33e04c0
use strict;
33e04c0
33e04c0
use Locale::gettext;
33e04c0
use POSIX;
33e04c0
33e04c0
$ENV{LANG} = 'C.UTF-8';
33e04c0
33e04c0
for my $lang (qw(fi_FI fr_FR en_US)) {
33e04c0
    $ENV{LANGUAGE} = $lang;
33e04c0
    setlocale(LC_MESSAGES, '');
33e04c0
    my $d = Locale::gettext->domain("bash");
33e04c0
    print $d->get('syntax error'), "\n";
33e04c0
}
33e04c0
33e04c0
Signed-off-by: Petr Písař <ppisar@redhat.com>
33e04c0
---
33e04c0
 locale.c | 21 +++++++++++++++++++++
33e04c0
 1 file changed, 21 insertions(+)
33e04c0
33e04c0
diff --git a/locale.c b/locale.c
33e04c0
index cdf125cee5..7ce7b3ed4c 100644
33e04c0
--- a/locale.c
33e04c0
+++ b/locale.c
33e04c0
@@ -402,6 +402,7 @@ S_category_name(const int category)
33e04c0
  * known at compile time; "do_setlocale_r", not known until run time  */
33e04c0
 #  define do_setlocale_c(cat, locale) my_setlocale(cat, locale)
33e04c0
 #  define do_setlocale_r(cat, locale) my_setlocale(cat, locale)
33e04c0
+#  define FIX_GLIBC_LC_MESSAGES_BUG(i)
33e04c0
 
33e04c0
 #else   /* Below uses POSIX 2008 */
33e04c0
 
33e04c0
@@ -415,6 +416,22 @@ S_category_name(const int category)
33e04c0
                         emulate_setlocale(cat, locale, cat ## _INDEX, TRUE)
33e04c0
 #  define do_setlocale_r(cat, locale) emulate_setlocale(cat, locale, 0, FALSE)
33e04c0
 
33e04c0
+#  if ! defined(__GLIBC__) || ! defined(USE_LOCALE_MESSAGES)
33e04c0
+
33e04c0
+#    define FIX_GLIBC_LC_MESSAGES_BUG(i)
33e04c0
+
33e04c0
+#  else /* Invalidate glibc cache of loaded translations, see [perl #134264] */
33e04c0
+
33e04c0
+#    include <libintl.h>
33e04c0
+#    define FIX_GLIBC_LC_MESSAGES_BUG(i)                                        \
33e04c0
+        STMT_START {                                                        \
33e04c0
+            if ((i) == LC_MESSAGES_INDEX) {                                 \
33e04c0
+                textdomain(textdomain(NULL));                               \
33e04c0
+            }                                                               \
33e04c0
+        } STMT_END
33e04c0
+
33e04c0
+#  endif
33e04c0
+
33e04c0
 /* A third array, parallel to the ones above to map from category to its
33e04c0
  * equivalent mask */
33e04c0
 const int category_masks[] = {
33e04c0
@@ -1158,6 +1175,8 @@ S_emulate_setlocale(const int category,
33e04c0
             Safefree(PL_curlocales[i]);
33e04c0
             PL_curlocales[i] = savepv(locale);
33e04c0
         }
33e04c0
+
33e04c0
+        FIX_GLIBC_LC_MESSAGES_BUG(LC_MESSAGES_INDEX);
33e04c0
     }
33e04c0
     else {
33e04c0
 
33e04c0
@@ -1172,6 +1191,8 @@ S_emulate_setlocale(const int category,
33e04c0
         /* Then update the category's record */
33e04c0
         Safefree(PL_curlocales[index]);
33e04c0
         PL_curlocales[index] = savepv(locale);
33e04c0
+
33e04c0
+        FIX_GLIBC_LC_MESSAGES_BUG(index);
33e04c0
     }
33e04c0
 
33e04c0
 #  endif
33e04c0
-- 
33e04c0
2.21.1
33e04c0