Skip to content

Commit bbff466

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 bbff466

File tree

3 files changed

+83
-21
lines changed

3 files changed

+83
-21
lines changed

Lib/test/test_locale.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,46 @@ 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+
oldlocale = locale.setlocale(locale.LC_CTYPE)
497+
self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
498+
try:
499+
locale.setlocale(locale.LC_CTYPE, 'tr_TR')
500+
except locale.Error:
501+
# Unsupported locale on this system
502+
self.skipTest('test needs Turkish locale')
503+
loc = locale.getlocale(locale.LC_CTYPE)
504+
if verbose:
505+
print('testing with %a' % (loc,), end=' ', flush=True)
506+
try:
507+
locale.setlocale(locale.LC_CTYPE, loc)
508+
except locale.Error as exc:
509+
# bpo-37945: setlocale(LC_CTYPE) fails with getlocale(LC_CTYPE)
510+
# and the tr_TR locale on Windows. getlocale() builds a locale
511+
# which is not recognize by setlocale().
512+
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
513+
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
514+
515+
def test_setlocale_long_encoding(self):
516+
# gh-137273: Debug assertion failure on Windows for long encoding.
517+
oldlocale = locale.setlocale(locale.LC_ALL)
518+
self.addCleanup(locale.setlocale, locale.LC_ALL, oldlocale)
519+
with self.assertRaises(locale.Error):
520+
locale.setlocale(locale.LC_CTYPE, 'en_US.' + 'x'*16)
521+
locale.setlocale(locale.LC_CTYPE, 'en_US.UTF-8')
522+
loc = locale.setlocale(locale.LC_ALL)
523+
self.assertIn('.UTF-8', loc)
524+
loc2 = loc.replace('UTF-8', 'x'*16, 1)
525+
with self.assertRaises(locale.Error):
526+
locale.setlocale(locale.LC_ALL, loc2)
527+
528+
489529
class TestMiscellaneous(unittest.TestCase):
490530
def test_defaults_UTF8(self):
491531
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
@@ -552,27 +592,6 @@ def test_setlocale_category(self):
552592
# crasher from bug #7419
553593
self.assertRaises(locale.Error, locale.setlocale, 12345)
554594

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-
576595
def test_invalid_locale_format_in_localetuple(self):
577596
with self.assertRaises(TypeError):
578597
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)