Просмотр исходного кода

extra/locale: skip locales the build host cannot provide

gen_locale harvests each locale's data (decimal_point, thousands_sep,
grouping, ctype tables, ...) from the *build host's* glibc via
setlocale(LC_ALL, name) + nl_langinfo().  If setlocale() fails -- because
the locale is not generated on the build host -- there is no valid data
to harvest for it, yet the old code only warned and carried on.  Since a
failed setlocale() leaves the previously selected locale active,
nl_langinfo() then returns *that* locale's data, baked into the entry
under the wrong name.

When the leftover data is a multibyte UTF-8 thousands_sep from an earlier
UTF-8 locale and the failing entry is an 8-bit one (e.g. a U+2019 ending
up in de_DE.ISO-8859-1), _locale_set_l() later decodes it in 8-bit mode,
gets a 1-byte length for the 3-byte sequence and aborts:

  locale.c: _locale_set_l: Assertion
    `base->thousands_sep[base->thousands_sep_len] == 0' failed

killing any program that selects the locale (and much of the testsuite).

Skip a locale entirely when setlocale() for it fails on the build host,
printing a clear message that names it.  Present locales are unaffected;
a skipped one is simply not built in, so selecting it returns NULL at run
time (as for any uninstalled locale) instead of shipping another
language's data.  The set of built-in locales therefore depends on what
the build host provides -- the messages show which to generate.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
Ramin Moussavi 1 неделя назад
Родитель
Сommit
a1dd02ab82
1 измененных файлов с 17 добавлено и 0 удалено
  1. 17 0
      extra/locale/gen_locale.c

+ 17 - 0
extra/locale/gen_locale.c

@@ -542,6 +542,23 @@ static void read_locale_list(void)
 /*  			   locales[num_locales].dot_cs, */
 /*  			   locales[num_locales].glibc_name */
 /*  			   ); */
+
+		/* The per-category data below is harvested from the build host via
+		 * setlocale()+nl_langinfo().  If the host cannot provide this locale,
+		 * setlocale() leaves the previously set (unrelated) locale active and
+		 * we would bake *that* locale's data -- e.g. a multibyte thousands_sep
+		 * from another language -- into this entry.  Skip it instead, with a
+		 * clear message so the missing host locale can be generated. */
+		if (!setlocale(LC_ALL, locales[num_locales].glibc_name)) {
+			fprintf(stderr,
+				"gen_locale: skipping locale '%s': not available on the build "
+				"host (generate it, e.g. via localedef / your distro's locale "
+				"package, to include it)\n",
+				locales[num_locales].glibc_name);
+			*line_buf = 0;
+			continue;
+		}
+
 		++num_locales;
 		*line_buf = 0;
 	} while (1);