am 36bacd23: Merge "Proper MB_CUR_MAX."
				
					
				
			* commit '36bacd237de931c48714d1a8aa4aa9522283e407': Proper MB_CUR_MAX.
This commit is contained in:
		| @@ -30,10 +30,27 @@ | |||||||
| #include <pthread.h> | #include <pthread.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #include "private/bionic_macros.h" | ||||||
|  |  | ||||||
| // We currently support a single locale, the "C" locale (also known as "POSIX"). | // We currently support a single locale, the "C" locale (also known as "POSIX"). | ||||||
|  |  | ||||||
|  | static bool __bionic_current_locale_is_utf8 = true; | ||||||
|  |  | ||||||
| struct __locale_t { | struct __locale_t { | ||||||
|   // Because we only support one locale, these are just tokens with no data. |   size_t mb_cur_max; | ||||||
|  |  | ||||||
|  |   __locale_t(size_t mb_cur_max) : mb_cur_max(mb_cur_max) { | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   __locale_t(const __locale_t* other) { | ||||||
|  |     if (other == LC_GLOBAL_LOCALE) { | ||||||
|  |       mb_cur_max = __bionic_current_locale_is_utf8 ? 4 : 1; | ||||||
|  |     } else { | ||||||
|  |       mb_cur_max = other->mb_cur_max; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   DISALLOW_COPY_AND_ASSIGN(__locale_t); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT; | static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT; | ||||||
| @@ -75,7 +92,14 @@ static void __locale_init() { | |||||||
|   g_locale.int_n_sign_posn = CHAR_MAX; |   g_locale.int_n_sign_posn = CHAR_MAX; | ||||||
| } | } | ||||||
|  |  | ||||||
| static bool __bionic_current_locale_is_utf8 = false; | size_t __mb_cur_max() { | ||||||
|  |   locale_t l = reinterpret_cast<locale_t>(pthread_getspecific(g_uselocale_key)); | ||||||
|  |   if (l == nullptr || l == LC_GLOBAL_LOCALE) { | ||||||
|  |     return __bionic_current_locale_is_utf8 ? 4 : 1; | ||||||
|  |   } else { | ||||||
|  |     return l->mb_cur_max; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| static bool __is_supported_locale(const char* locale) { | static bool __is_supported_locale(const char* locale) { | ||||||
|   return (strcmp(locale, "") == 0 || |   return (strcmp(locale, "") == 0 || | ||||||
| @@ -85,25 +109,17 @@ static bool __is_supported_locale(const char* locale) { | |||||||
|           strcmp(locale, "POSIX") == 0); |           strcmp(locale, "POSIX") == 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| static locale_t __new_locale() { |  | ||||||
|   return reinterpret_cast<locale_t>(malloc(sizeof(__locale_t))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lconv* localeconv() { | lconv* localeconv() { | ||||||
|   pthread_once(&g_locale_once, __locale_init); |   pthread_once(&g_locale_once, __locale_init); | ||||||
|   return &g_locale; |   return &g_locale; | ||||||
| } | } | ||||||
|  |  | ||||||
| locale_t duplocale(locale_t l) { | locale_t duplocale(locale_t l) { | ||||||
|   locale_t clone = __new_locale(); |   return new __locale_t(l); | ||||||
|   if (clone != NULL && l != LC_GLOBAL_LOCALE) { |  | ||||||
|     *clone = *l; |  | ||||||
|   } |  | ||||||
|   return clone; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void freelocale(locale_t l) { | void freelocale(locale_t l) { | ||||||
|   free(l); |   delete l; | ||||||
| } | } | ||||||
|  |  | ||||||
| locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/) { | locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/) { | ||||||
| @@ -118,7 +134,7 @@ locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/ | |||||||
|     return NULL; |     return NULL; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return __new_locale(); |   return new __locale_t(strstr(locale_name, "UTF-8") != NULL ? 4 : 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| char* setlocale(int category, const char* locale_name) { | char* setlocale(int category, const char* locale_name) { | ||||||
|   | |||||||
| @@ -161,7 +161,8 @@ extern int      mbtowc(wchar_t *, const char *, size_t); | |||||||
| extern int	wctomb(char *, wchar_t); | extern int	wctomb(char *, wchar_t); | ||||||
| extern size_t	wcstombs(char *, const wchar_t *, size_t); | extern size_t	wcstombs(char *, const wchar_t *, size_t); | ||||||
|  |  | ||||||
| #define MB_CUR_MAX 4U | extern size_t __mb_cur_max(void); | ||||||
|  | #define MB_CUR_MAX __mb_cur_max() | ||||||
|  |  | ||||||
| __END_DECLS | __END_DECLS | ||||||
|  |  | ||||||
|   | |||||||
| @@ -48,8 +48,8 @@ TEST(locale, localeconv) { | |||||||
| } | } | ||||||
|  |  | ||||||
| TEST(locale, setlocale) { | TEST(locale, setlocale) { | ||||||
|   EXPECT_STREQ("C", setlocale(LC_ALL, NULL)); |   EXPECT_STREQ("C.UTF-8", setlocale(LC_ALL, NULL)); | ||||||
|   EXPECT_STREQ("C", setlocale(LC_CTYPE, NULL)); |   EXPECT_STREQ("C.UTF-8", setlocale(LC_CTYPE, NULL)); | ||||||
|  |  | ||||||
|   errno = 0; |   errno = 0; | ||||||
|   EXPECT_EQ(NULL, setlocale(-1, NULL)); |   EXPECT_EQ(NULL, setlocale(-1, NULL)); | ||||||
| @@ -105,3 +105,20 @@ TEST(locale, uselocale) { | |||||||
|  |  | ||||||
|   EXPECT_EQ(n, uselocale(NULL)); |   EXPECT_EQ(n, uselocale(NULL)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | TEST(locale, mb_cur_max) { | ||||||
|  |   // We can't reliably test the behavior with setlocale(3) or the behavior for | ||||||
|  |   // initial program conditions because (unless we're the only test that was | ||||||
|  |   // run), another test has almost certainly called uselocale(3) in this thread. | ||||||
|  |   // See b/16685652. | ||||||
|  |   locale_t cloc = newlocale(LC_ALL, "C", 0); | ||||||
|  |   locale_t cloc_utf8 = newlocale(LC_ALL, "C.UTF-8", 0); | ||||||
|  |  | ||||||
|  |   uselocale(cloc); | ||||||
|  |   ASSERT_EQ(1U, MB_CUR_MAX); | ||||||
|  |   uselocale(cloc_utf8); | ||||||
|  |   ASSERT_EQ(4U, MB_CUR_MAX); | ||||||
|  |  | ||||||
|  |   freelocale(cloc); | ||||||
|  |   freelocale(cloc_utf8); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -427,6 +427,9 @@ TEST(stdio, snprintf_negative_zero_5084292) { | |||||||
| } | } | ||||||
|  |  | ||||||
| TEST(stdio, snprintf_utf8_15439554) { | TEST(stdio, snprintf_utf8_15439554) { | ||||||
|  |   locale_t cloc = newlocale(LC_ALL, "C.UTF-8", 0); | ||||||
|  |   uselocale(cloc); | ||||||
|  |  | ||||||
|   // http://b/15439554 |   // http://b/15439554 | ||||||
|   char buf[BUFSIZ]; |   char buf[BUFSIZ]; | ||||||
|  |  | ||||||
| @@ -442,6 +445,8 @@ TEST(stdio, snprintf_utf8_15439554) { | |||||||
|   // 4-byte character. |   // 4-byte character. | ||||||
|   snprintf(buf, sizeof(buf), "%d\xf0\xa4\xad\xa2%d", 1, 2); |   snprintf(buf, sizeof(buf), "%d\xf0\xa4\xad\xa2%d", 1, 2); | ||||||
|   EXPECT_STREQ("1𤭢2", buf); |   EXPECT_STREQ("1𤭢2", buf); | ||||||
|  |  | ||||||
|  |   freelocale(cloc); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(stdio, fprintf_failures_7229520) { | TEST(stdio, fprintf_failures_7229520) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Dan Albert
					Dan Albert