Skip to content

Commit c6dbeb8

Browse files
gh-137273: Fix debug assertion failure in locale.setlocale() on Windows
It happened when there were at least 16 characters after dot in the locale name.
1 parent 9ced5c4 commit c6dbeb8

File tree

3 files changed

+81
-21
lines changed

3 files changed

+81
-21
lines changed

Lib/test/test_locale.py

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,44 @@ def test_japanese(self):
486486
self.check('jp_jp', 'ja_JP.eucJP')
487487

488488

489+
class TestRealLocales(unittest.TestCase):
490+
def setUp(self):
491+
oldlocale = locale.setlocale(locale.LC_CTYPE)
492+
self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
493+
494+
def test_getsetlocale_issue1813(self):
495+
# Issue #1813: setting and getting the locale under a Turkish locale
496+
try:
497+
locale.setlocale(locale.LC_CTYPE, 'tr_TR')
498+
except locale.Error:
499+
# Unsupported locale on this system
500+
self.skipTest('test needs Turkish locale')
501+
loc = locale.getlocale(locale.LC_CTYPE)
502+
if verbose:
503+
print('testing with %a' % (loc,), end=' ', flush=True)
504+
try:
505+
locale.setlocale(locale.LC_CTYPE, loc)
506+
except locale.Error as exc:
507+
# bpo-37945: setlocale(LC_CTYPE) fails with getlocale(LC_CTYPE)
508+
# and the tr_TR locale on Windows. getlocale() builds a locale
509+
# which is not recognize by setlocale().
510+
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
511+
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
512+
513+
def test_setlocale_long_encoding(self):
514+
# gh-137273: Debug assertion failure on Windows for long encoding.
515+
oldlocale = locale.setlocale(locale.LC_ALL)
516+
self.addCleanup(locale.setlocale, locale.LC_ALL, oldlocale)
517+
with self.assertRaises(locale.Error):
518+
locale.setlocale(locale.LC_CTYPE, 'en_US.' + 'x'*16)
519+
locale.setlocale(locale.LC_CTYPE, 'en_US.UTF-8')
520+
loc = locale.setlocale(locale.LC_ALL)
521+
self.assertIn('.UTF-8', loc)
522+
loc2 = loc.replace('UTF-8', 'x'*16, 1)
523+
with self.assertRaises(locale.Error):
524+
locale.setlocale(locale.LC_ALL, loc2)
525+
526+
489527
class TestMiscellaneous(unittest.TestCase):
490528
def test_defaults_UTF8(self):
491529
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
@@ -552,27 +590,6 @@ def test_setlocale_category(self):
552590
# crasher from bug #7419
553591
self.assertRaises(locale.Error, locale.setlocale, 12345)
554592

555-
def test_getsetlocale_issue1813(self):
556-
# Issue #1813: setting and getting the locale under a Turkish locale
557-
oldlocale = locale.setlocale(locale.LC_CTYPE)
558-
self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
559-
try:
560-
locale.setlocale(locale.LC_CTYPE, 'tr_TR')
561-
except locale.Error:
562-
# Unsupported locale on this system
563-
self.skipTest('test needs Turkish locale')
564-
loc = locale.getlocale(locale.LC_CTYPE)
565-
if verbose:
566-
print('testing with %a' % (loc,), end=' ', flush=True)
567-
try:
568-
locale.setlocale(locale.LC_CTYPE, loc)
569-
except locale.Error as exc:
570-
# bpo-37945: setlocale(LC_CTYPE) fails with getlocale(LC_CTYPE)
571-
# and the tr_TR locale on Windows. getlocale() builds a locale
572-
# which is not recognize by setlocale().
573-
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
574-
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
575-
576593
def test_invalid_locale_format_in_localetuple(self):
577594
with self.assertRaises(TypeError):
578595
locale.setlocale(locale.LC_ALL, b'fi_FI')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix debug assertion failure in :func:`locale.setlocale` on Windows.

Modules/_localemodule.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,36 @@ copy_grouping(const char* s)
8787
return result;
8888
}
8989

90+
#if defined(MS_WINDOWS)
91+
static int
92+
check_locale_name(const char *locale, const char *end)
93+
{
94+
size_t len = end ? (size_t)(end - locale) : strlen(locale);
95+
const char *dot = memchr(locale, '.', len);
96+
if (dot && locale + len - dot > 16) {
97+
return -1;
98+
}
99+
return 0;
100+
}
101+
102+
static int
103+
check_locale_name_all(const char *locale)
104+
{
105+
const char *start = locale;
106+
while (1) {
107+
const char *end = strchr(start, ';');
108+
if (check_locale_name(start, end) < 0) {
109+
return -1;
110+
}
111+
if (end == NULL) {
112+
break;
113+
}
114+
start = end + 1;
115+
}
116+
return 0;
117+
}
118+
#endif
119+
90120
/*[clinic input]
91121
_locale.setlocale
92122
@@ -111,6 +141,18 @@ _locale_setlocale_impl(PyObject *module, int category, const char *locale)
111141
"invalid locale category");
112142
return NULL;
113143
}
144+
if (locale) {
145+
if ((category == LC_ALL
146+
? check_locale_name_all(locale)
147+
: check_locale_name(locale, NULL)) < 0)
148+
{
149+
/* Debug assertion failure on Windows.
150+
* _Py_BEGIN_SUPPRESS_IPH/_Py_END_SUPPRESS_IPH do not help. */
151+
PyErr_SetString(get_locale_state(module)->Error,
152+
"unsupported locale setting");
153+
return NULL;
154+
}
155+
}
114156
#endif
115157

116158
if (locale) {

0 commit comments

Comments
 (0)