Fix duplocale (libc/locale/duplocale.c) which fails to properly call __loadlocale

Problem:

  After  passing  locales  created  by  'duplocale'   to   'uselocale',
  referencing   'MB_CUR_MAX',   which   is   actually   expanded    to
  '__locale_mb_cur_max()' by preprocessors, causes segmentation faults.
  Direct use of locales from 'newlocale' does not  cause  the  problem.
  This is the problem of 'duplocale'.

  $ echo $LANG
  ja_JP.UTF-8
  $ cat test.c
  #include <stdlib.h>
  #include <locale.h>

  volatile int var;

  int main(void) {
    locale_t const loc = newlocale(LC_ALL_MASK, "", NULL);
    locale_t const dup = duplocale(loc);
    locale_t const old = uselocale(dup);
    var = MB_CUR_MAX; /* <-- crashes here */
    uselocale(old);
    freelocale(dup);
    freelocale(loc);
    return 0;
  }
  $ gcc test.c
  $ ./a
  Segmentation fault (core dumped)

  # Note: "core dumped" in the above message was  actually written  in
  # Japanese, but I translated the part to post a mail in English.

Bug:

  In the beginning of '__loadlocale' (newlib/libc/locale/locale.c:501),
  there is a code which checks if the operations can be skipped:

  > /* Avoid doing everything twice if nothing has changed. */
  > if (!strcmp (new_locale, loc->categories[category]))
  >   return loc->categories[category];

  While,   in   the   function   '_duplocale_r'    (newlib/libc/locale/
  duplocale.c), '__loadlocale'  is  called  as  in  the  quoted  codes:

  > /* If the object is not a "C" locale category, copy it.  Just call
  >    __loadlocale.  It knows what to do to replicate the category. */
  > tmp_locale.lc_cat[i].ptr = NULL;
  > tmp_locale.lc_cat[i].buf = NULL;
  > if (!__loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
  >   goto error;

  This call of '__loadlocale' results in the skip check being

    !strcmp(tmp_locale.categories[i], tmp_locale.categories[i]),

  which is always true. This  means  that  the  actual  operations  of
  '__loadLocale' will never be performed for 'duplocale'.

Fix:

  The call of '__loadlocale' in '_duplocale_r' is modified.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Koichi Murase 2017-03-12 01:27:26 +09:00 committed by Corinna Vinschen
parent 02011278e0
commit 973f766f6e
2 changed files with 7 additions and 2 deletions

View File

@ -64,7 +64,8 @@ _duplocale_r (struct _reent *p, struct __locale_t *locobj)
__loadlocale. It knows what to do to replicate the category. */
tmp_locale.lc_cat[i].ptr = NULL;
tmp_locale.lc_cat[i].buf = NULL;
if (!__loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
tmp_locale.categories[i][0] = '\0'; /* __loadlocale tests this! */
if (!__loadlocale (&tmp_locale, i, locobj->categories[i]))
goto error;
}
#endif /* __HAVE_LOCALE_INFO__ */

View File

@ -498,7 +498,11 @@ __loadlocale (struct __locale_t *loc, int category, const char *new_locale)
mbtowc_p l_mbtowc;
int cjknarrow = 0;
/* Avoid doing everything twice if nothing has changed. */
/* Avoid doing everything twice if nothing has changed.
duplocale relies on this test to go wrong so the locale is actually
duplicated when required. Any change here has to be synced with a
matching change in duplocale. */
if (!strcmp (new_locale, loc->categories[category]))
return loc->categories[category];