Skip to content

Commit 75f83f4

Browse files
committed
gh-130567: fix strxfrm memory allocation
The posix specification does not define that wcsxfrm should return needed buffer size, it just says: If the value returned is n or more, the contents of the array pointed to by ws1 are unspecified. Therefore double the allocation when the original call has failed. It might also make sense to increase the allocation repeatedly, but that would make the code more complex.
1 parent fda056e commit 75f83f4

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

Lib/test/test_locale.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,17 @@ def test_strcoll_with_diacritic(self):
371371
def test_strxfrm_with_diacritic(self):
372372
self.assertLess(locale.strxfrm('à'), locale.strxfrm('b'))
373373

374+
@unittest.skipIf(sys.platform.startswith('aix'),
375+
'bpo-29972: broken test on AIX')
376+
@unittest.skipIf(
377+
is_emscripten or is_wasi,
378+
"musl libc issue on Emscripten/WASI, bpo-46390"
379+
)
380+
@unittest.skipIf(sys.platform.startswith("netbsd"),
381+
"gh-124108: NetBSD doesn't support UTF-8 for LC_COLLATE")
382+
def test_strxfrm_non_latin_1(self):
383+
self.assertLess(locale.strxfrm('s'), locale.strxfrm('š'))
384+
374385

375386
class NormalizeTest(unittest.TestCase):
376387
def check(self, localename, expected):

Modules/_localemodule.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,14 @@ _locale_strxfrm_impl(PyObject *module, PyObject *str)
422422
goto exit;
423423
}
424424
if (n2 >= (size_t)n1) {
425-
/* more space needed */
426-
wchar_t * new_buf = PyMem_Realloc(buf, (n2+1)*sizeof(wchar_t));
425+
/* more space needed, some implementations return needed size while
426+
others just buffer length and it's up to the caller to figure
427+
out needed buffer size */
428+
size_t new_buf_size = n2 + 1;
429+
if (n1 * 2 > new_buf_size) {
430+
new_buf_size = n1 * 2;
431+
}
432+
wchar_t * new_buf = PyMem_Realloc(buf, new_buf_size * sizeof(wchar_t));
427433
if (!new_buf) {
428434
PyErr_NoMemory();
429435
goto exit;

0 commit comments

Comments
 (0)