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