From 52d1d6a50dbe687f788b93ccc4a754bbf6ee0d46 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 26 Dec 2009 14:30:21 +0100 Subject: [PATCH] localename: Fix storage allocation of gl_locale_name_thread's result. --- ChangeLog | 14 ++++ lib/localename.c | 32 ++++++--- modules/localename-tests | 1 + tests/test-localename.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index ec484dc1f..8eab82e5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2009-12-26 Bruno Haible + localename: Fix storage allocation of gl_locale_name_thread's result. + * lib/localename.c (SIZE_BITS, string_hash, struct hash_node, + HASH_TABLE_SIZE, struniq_hash_table, struniq_lock, struniq): Define on + all platforms that have 'uselocale'. + (gl_locale_name_thread_unsafe): New function, extracted from + gl_locale_name_thread. + (gl_locale_name_thread): Call struniq on all platforms that have + 'uselocale'. + * tests/test-localename.c (test_locale_name_thread): Check that the + resulting strings are permanently allocated. + * modules/localename-tests (Depends-on): Add strdup. + +2009-12-26 Bruno Haible + * tests/test-localename.c (categories): Fill in the strings. 2009-12-26 Jim Meyering diff --git a/lib/localename.c b/lib/localename.c index 4b77c95fa..03328b9ec 100644 --- a/lib/localename.c +++ b/lib/localename.c @@ -2507,7 +2507,7 @@ gl_locale_name_from_win32_LCID (LCID lcid) #endif -#if defined __APPLE__ && defined __MACH__ && HAVE_USELOCALE /* MacOS X */ +#if HAVE_USELOCALE /* glibc or MacOS X */ /* Simple hash set of strings. We don't want to drag in lots of hash table code here. */ @@ -2592,8 +2592,13 @@ struniq (const char *string) #endif +/* Like gl_locale_name_thread, except that the result is not in storage of + indefinite extent. */ +#if !defined IN_LIBINTL +static +#endif const char * -gl_locale_name_thread (int category, const char *categoryname) +gl_locale_name_thread_unsafe (int category, const char *categoryname) { #if HAVE_USELOCALE { @@ -2686,26 +2691,26 @@ gl_locale_name_thread (int category, const char *categoryname) switch (category) { case LC_CTYPE: - return struniq (tlp->__lc_ctype->__ctype_encoding); + return tlp->__lc_ctype->__ctype_encoding; case LC_NUMERIC: return tlp->_numeric_using_locale - ? struniq (tlp->__lc_numeric->_numeric_locale_buf) + ? tlp->__lc_numeric->_numeric_locale_buf : "C"; case LC_TIME: return tlp->_time_using_locale - ? struniq (tlp->__lc_time->_time_locale_buf) + ? tlp->__lc_time->_time_locale_buf : "C"; case LC_COLLATE: return !tlp->__collate_load_error - ? struniq (tlp->__lc_collate->__encoding) + ? tlp->__lc_collate->__encoding : "C"; case LC_MONETARY: return tlp->_monetary_using_locale - ? struniq (tlp->__lc_monetary->_monetary_locale_buf) + ? tlp->__lc_monetary->_monetary_locale_buf : "C"; case LC_MESSAGES: return tlp->_messages_using_locale - ? struniq (tlp->__lc_messages->_messages_locale_buf) + ? tlp->__lc_messages->_messages_locale_buf : "C"; default: /* We shouldn't get here. */ return ""; @@ -2717,6 +2722,17 @@ gl_locale_name_thread (int category, const char *categoryname) return NULL; } +const char * +gl_locale_name_thread (int category, const char *categoryname) +{ +#if HAVE_USELOCALE + const char *name = gl_locale_name_thread_unsafe (category, categoryname); + if (name != NULL) + return struniq (name); +#endif + return NULL; +} + /* XPG3 defines the result of 'setlocale (category, NULL)' as: "Directs 'setlocale()' to query 'category' and return the current setting of 'local'." diff --git a/modules/localename-tests b/modules/localename-tests index 3fbca140d..3b53c6c14 100644 --- a/modules/localename-tests +++ b/modules/localename-tests @@ -6,6 +6,7 @@ Depends-on: locale setenv unsetenv +strdup configure.ac: AC_CHECK_FUNCS_ONCE([newlocale]) diff --git a/tests/test-localename.c b/tests/test-localename.c index 3a615aaf0..38fc33040 100644 --- a/tests/test-localename.c +++ b/tests/test-localename.c @@ -274,6 +274,181 @@ test_locale_name_thread (void) } } } + + /* Check that gl_locale_name_thread returns a string that is allocated with + indefinite extent. */ + { + /* Try many locale names in turn, in order to defeat possible caches. */ + static const char * const choices[] = + { + "C", + "POSIX", + "af_ZA", + "af_ZA.UTF-8", + "am_ET", + "am_ET.UTF-8", + "be_BY", + "be_BY.UTF-8", + "bg_BG", + "bg_BG.UTF-8", + "ca_ES", + "ca_ES.UTF-8", + "cs_CZ", + "cs_CZ.UTF-8", + "da_DK", + "da_DK.UTF-8", + "de_AT", + "de_AT.UTF-8", + "de_CH", + "de_CH.UTF-8", + "de_DE", + "de_DE.UTF-8", + "el_GR", + "el_GR.UTF-8", + "en_AU", + "en_AU.UTF-8", + "en_CA", + "en_CA.UTF-8", + "en_GB", + "en_GB.UTF-8", + "en_IE", + "en_IE.UTF-8", + "en_NZ", + "en_NZ.UTF-8", + "en_US", + "en_US.UTF-8", + "es_ES", + "es_ES.UTF-8", + "et_EE", + "et_EE.UTF-8", + "eu_ES", + "eu_ES.UTF-8", + "fi_FI", + "fi_FI.UTF-8", + "fr_BE", + "fr_BE.UTF-8", + "fr_CA", + "fr_CA.UTF-8", + "fr_CH", + "fr_CH.UTF-8", + "fr_FR", + "fr_FR.UTF-8", + "he_IL", + "he_IL.UTF-8", + "hr_HR", + "hr_HR.UTF-8", + "hu_HU", + "hu_HU.UTF-8", + "hy_AM", + "is_IS", + "is_IS.UTF-8", + "it_CH", + "it_CH.UTF-8", + "it_IT", + "it_IT.UTF-8", + "ja_JP.UTF-8", + "kk_KZ", + "kk_KZ.UTF-8", + "ko_KR.UTF-8", + "lt_LT", + "lt_LT.UTF-8", + "nl_BE", + "nl_BE.UTF-8", + "nl_NL", + "nl_NL.UTF-8", + "no_NO", + "no_NO.UTF-8", + "pl_PL", + "pl_PL.UTF-8", + "pt_BR", + "pt_BR.UTF-8", + "pt_PT", + "pt_PT.UTF-8", + "ro_RO", + "ro_RO.UTF-8", + "ru_RU", + "ru_RU.UTF-8", + "sk_SK", + "sk_SK.UTF-8", + "sl_SI", + "sl_SI.UTF-8", + "sv_SE", + "sv_SE.UTF-8", + "tr_TR", + "tr_TR.UTF-8", + "uk_UA", + "uk_UA.UTF-8", + "zh_CN", + "zh_CN.UTF-8", + "zh_HK", + "zh_HK.UTF-8", + "zh_TW", + "zh_TW.UTF-8" + }; + /* Remember which locales are available. */ + unsigned char /* bool */ available[SIZEOF (choices)]; + /* Array of remembered results of gl_locale_name_thread. */ + const char *unsaved_names[SIZEOF (choices)][SIZEOF (categories)]; + /* Array of remembered results of gl_locale_name_thread, stored in safe + memory. */ + char *saved_names[SIZEOF (choices)][SIZEOF (categories)]; + unsigned int j; + + for (j = 0; j < SIZEOF (choices); j++) + { + locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL); + available[j] = (locale != NULL); + if (locale != NULL) + { + unsigned int i; + + uselocale (locale); + for (i = 0; i < SIZEOF (categories); i++) + { + unsaved_names[j][i] = gl_locale_name_thread (categories[i].cat, categories[i].string); + saved_names[j][i] = strdup (unsaved_names[j][i]); + } + uselocale (LC_GLOBAL_LOCALE); + freelocale (locale); + } + } + /* Verify the unsaved_names are still valid. */ + for (j = 0; j < SIZEOF (choices); j++) + { + unsigned int i; + + for (i = 0; i < SIZEOF (categories); i++) + ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0); + } + /* Allocate many locales, without freeing them. This is an attempt at + overwriting as much of the previously allocated memory as possible. */ + for (j = SIZEOF (choices); j > 0; ) + { + j--; + if (available[j]) + { + locale_t locale = newlocale (LC_ALL_MASK, choices[j], NULL); + unsigned int i; + + ASSERT (locale != NULL); + uselocale (locale); + for (i = 0; i < SIZEOF (categories); i++) + { + const char *name = gl_locale_name_thread (categories[i].cat, categories[i].string); + ASSERT (strcmp (unsaved_names[j][i], name) == 0); + } + uselocale (LC_GLOBAL_LOCALE); + } + } + /* Verify the unsaved_names are still valid. */ + for (j = 0; j < SIZEOF (choices); j++) + { + unsigned int i; + + for (i = 0; i < SIZEOF (categories); i++) + ASSERT (strcmp (unsaved_names[j][i], saved_names[j][i]) == 0); + } + } #else /* Check that gl_locale_name_thread always returns NULL. */ ASSERT (gl_locale_name_thread (LC_CTYPE, "LC_CTYPE") == NULL); -- 2.11.0