mirror of
https://github.com/python/cpython.git
synced 2025-08-22 01:35:16 +00:00
[3.13] gh-137273: Fix debug assertion failure in locale.setlocale() on Windows (GH-137300) (GH-137306)
Some checks are pending
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Check if the ABI has changed (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
Some checks are pending
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / Check if the ABI has changed (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
It happened when there were at least 16 characters after dot in the
locale name.
(cherry picked from commit 718e0c89ba
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
6a217cef27
commit
a32bd11cb0
3 changed files with 97 additions and 21 deletions
|
@ -5,6 +5,7 @@ from test.support.import_helper import import_fresh_module
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import unittest
|
import unittest
|
||||||
import locale
|
import locale
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
import codecs
|
||||||
|
|
||||||
|
@ -487,6 +488,54 @@ class NormalizeTest(unittest.TestCase):
|
||||||
self.check('jp_jp', 'ja_JP.eucJP')
|
self.check('jp_jp', 'ja_JP.eucJP')
|
||||||
|
|
||||||
|
|
||||||
|
class TestRealLocales(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
oldlocale = locale.setlocale(locale.LC_CTYPE)
|
||||||
|
self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
|
||||||
|
|
||||||
|
def test_getsetlocale_issue1813(self):
|
||||||
|
# Issue #1813: setting and getting the locale under a Turkish locale
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_CTYPE, 'tr_TR')
|
||||||
|
except locale.Error:
|
||||||
|
# Unsupported locale on this system
|
||||||
|
self.skipTest('test needs Turkish locale')
|
||||||
|
loc = locale.getlocale(locale.LC_CTYPE)
|
||||||
|
if verbose:
|
||||||
|
print('testing with %a' % (loc,), end=' ', flush=True)
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_CTYPE, loc)
|
||||||
|
except locale.Error as exc:
|
||||||
|
# bpo-37945: setlocale(LC_CTYPE) fails with getlocale(LC_CTYPE)
|
||||||
|
# and the tr_TR locale on Windows. getlocale() builds a locale
|
||||||
|
# which is not recognize by setlocale().
|
||||||
|
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
|
||||||
|
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
|
||||||
|
def test_setlocale_long_encoding(self):
|
||||||
|
with self.assertRaises(locale.Error):
|
||||||
|
locale.setlocale(locale.LC_CTYPE, 'English.%016d' % 1252)
|
||||||
|
locale.setlocale(locale.LC_CTYPE, 'English.%015d' % 1252)
|
||||||
|
loc = locale.setlocale(locale.LC_ALL)
|
||||||
|
self.assertIn('.1252', loc)
|
||||||
|
loc2 = loc.replace('.1252', '.%016d' % 1252, 1)
|
||||||
|
with self.assertRaises(locale.Error):
|
||||||
|
locale.setlocale(locale.LC_ALL, loc2)
|
||||||
|
loc2 = loc.replace('.1252', '.%015d' % 1252, 1)
|
||||||
|
locale.setlocale(locale.LC_ALL, loc2)
|
||||||
|
|
||||||
|
# gh-137273: Debug assertion failure on Windows for long encoding.
|
||||||
|
with self.assertRaises(locale.Error):
|
||||||
|
locale.setlocale(locale.LC_CTYPE, 'en_US.' + 'x'*16)
|
||||||
|
locale.setlocale(locale.LC_CTYPE, 'en_US.UTF-8')
|
||||||
|
loc = locale.setlocale(locale.LC_ALL)
|
||||||
|
self.assertIn('.UTF-8', loc)
|
||||||
|
loc2 = loc.replace('.UTF-8', '.' + 'x'*16, 1)
|
||||||
|
with self.assertRaises(locale.Error):
|
||||||
|
locale.setlocale(locale.LC_ALL, loc2)
|
||||||
|
|
||||||
|
|
||||||
class TestMiscellaneous(unittest.TestCase):
|
class TestMiscellaneous(unittest.TestCase):
|
||||||
def test_defaults_UTF8(self):
|
def test_defaults_UTF8(self):
|
||||||
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
|
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
|
||||||
|
@ -565,27 +614,6 @@ class TestMiscellaneous(unittest.TestCase):
|
||||||
# crasher from bug #7419
|
# crasher from bug #7419
|
||||||
self.assertRaises(locale.Error, locale.setlocale, 12345)
|
self.assertRaises(locale.Error, locale.setlocale, 12345)
|
||||||
|
|
||||||
def test_getsetlocale_issue1813(self):
|
|
||||||
# Issue #1813: setting and getting the locale under a Turkish locale
|
|
||||||
oldlocale = locale.setlocale(locale.LC_CTYPE)
|
|
||||||
self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale)
|
|
||||||
try:
|
|
||||||
locale.setlocale(locale.LC_CTYPE, 'tr_TR')
|
|
||||||
except locale.Error:
|
|
||||||
# Unsupported locale on this system
|
|
||||||
self.skipTest('test needs Turkish locale')
|
|
||||||
loc = locale.getlocale(locale.LC_CTYPE)
|
|
||||||
if verbose:
|
|
||||||
print('testing with %a' % (loc,), end=' ', flush=True)
|
|
||||||
try:
|
|
||||||
locale.setlocale(locale.LC_CTYPE, loc)
|
|
||||||
except locale.Error as exc:
|
|
||||||
# bpo-37945: setlocale(LC_CTYPE) fails with getlocale(LC_CTYPE)
|
|
||||||
# and the tr_TR locale on Windows. getlocale() builds a locale
|
|
||||||
# which is not recognize by setlocale().
|
|
||||||
self.skipTest(f"setlocale(LC_CTYPE, {loc!r}) failed: {exc!r}")
|
|
||||||
self.assertEqual(loc, locale.getlocale(locale.LC_CTYPE))
|
|
||||||
|
|
||||||
def test_invalid_locale_format_in_localetuple(self):
|
def test_invalid_locale_format_in_localetuple(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
locale.setlocale(locale.LC_ALL, b'fi_FI')
|
locale.setlocale(locale.LC_ALL, b'fi_FI')
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix debug assertion failure in :func:`locale.setlocale` on Windows.
|
|
@ -87,6 +87,41 @@ copy_grouping(const char* s)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MS_WINDOWS)
|
||||||
|
|
||||||
|
// 16 is the number of elements in the szCodePage field
|
||||||
|
// of the __crt_locale_strings structure.
|
||||||
|
#define MAX_CP_LEN 15
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_locale_name(const char *locale, const char *end)
|
||||||
|
{
|
||||||
|
size_t len = end ? (size_t)(end - locale) : strlen(locale);
|
||||||
|
const char *dot = memchr(locale, '.', len);
|
||||||
|
if (dot && locale + len - dot - 1 > MAX_CP_LEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_locale_name_all(const char *locale)
|
||||||
|
{
|
||||||
|
const char *start = locale;
|
||||||
|
while (1) {
|
||||||
|
const char *end = strchr(start, ';');
|
||||||
|
if (check_locale_name(start, end) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (end == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_locale.setlocale
|
_locale.setlocale
|
||||||
|
|
||||||
|
@ -111,6 +146,18 @@ _locale_setlocale_impl(PyObject *module, int category, const char *locale)
|
||||||
"invalid locale category");
|
"invalid locale category");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (locale) {
|
||||||
|
if ((category == LC_ALL
|
||||||
|
? check_locale_name_all(locale)
|
||||||
|
: check_locale_name(locale, NULL)) < 0)
|
||||||
|
{
|
||||||
|
/* Debug assertion failure on Windows.
|
||||||
|
* _Py_BEGIN_SUPPRESS_IPH/_Py_END_SUPPRESS_IPH do not help. */
|
||||||
|
PyErr_SetString(get_locale_state(module)->Error,
|
||||||
|
"unsupported locale setting");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (locale) {
|
if (locale) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue