Skip to content

Commit 04cc014

Browse files
gh-106844: Fix issues in _winapi.LCMapStringEx (GH-107832)
* Strings with length from 2**31-1 to 2**32-2 always caused MemoryError, it doesn't matter how much memory is available. * Strings with length exactly 2**32-1 caused OSError. * Strings longer than 2**32-1 characters were truncated due to integer overflow bug. * Strings containing the null character were truncated at the first null character. Now strings longer than 2**31-1 characters caused OverflowError and the null character is allowed.
1 parent a39f0a3 commit 04cc014

File tree

4 files changed

+32
-16
lines changed

4 files changed

+32
-16
lines changed

Lib/test/test_ntpath.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,7 @@ def test_path_normcase(self):
10361036
self._check_function(self.path.normcase)
10371037
if sys.platform == 'win32':
10381038
self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ')
1039+
self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def')
10391040

10401041
def test_path_isabs(self):
10411042
self._check_function(self.path.isabs)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix integer overflow and truncating by the null character in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`.

Modules/_winapi.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,40 +1539,56 @@ _winapi.LCMapStringEx
15391539
15401540
locale: LPCWSTR
15411541
flags: DWORD
1542-
src: LPCWSTR
1542+
src: unicode
15431543
15441544
[clinic start generated code]*/
15451545

15461546
static PyObject *
15471547
_winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
1548-
LPCWSTR src)
1549-
/*[clinic end generated code: output=cf4713d80e2b47c9 input=9fe26f95d5ab0001]*/
1548+
PyObject *src)
1549+
/*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/
15501550
{
15511551
if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
15521552
LCMAP_SORTKEY)) {
15531553
return PyErr_Format(PyExc_ValueError, "unsupported flags");
15541554
}
15551555

1556-
int dest_size = LCMapStringEx(locale, flags, src, -1, NULL, 0,
1556+
Py_ssize_t src_size;
1557+
wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
1558+
if (!src_) {
1559+
return NULL;
1560+
}
1561+
if (src_size > INT_MAX) {
1562+
PyMem_Free(src_);
1563+
PyErr_SetString(PyExc_OverflowError, "input string is too long");
1564+
return NULL;
1565+
}
1566+
1567+
int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0,
15571568
NULL, NULL, 0);
1558-
if (dest_size == 0) {
1559-
return PyErr_SetFromWindowsErr(0);
1569+
if (dest_size <= 0) {
1570+
DWORD error = GetLastError();
1571+
PyMem_Free(src_);
1572+
return PyErr_SetFromWindowsErr(error);
15601573
}
15611574

15621575
wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
15631576
if (dest == NULL) {
1577+
PyMem_Free(src_);
15641578
return PyErr_NoMemory();
15651579
}
15661580

1567-
int nmapped = LCMapStringEx(locale, flags, src, -1, dest, dest_size,
1581+
int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size,
15681582
NULL, NULL, 0);
1569-
if (nmapped == 0) {
1583+
if (nmapped <= 0) {
15701584
DWORD error = GetLastError();
1585+
PyMem_Free(src_);
15711586
PyMem_DEL(dest);
15721587
return PyErr_SetFromWindowsErr(error);
15731588
}
15741589

1575-
PyObject *ret = PyUnicode_FromWideChar(dest, dest_size - 1);
1590+
PyMem_Free(src_);
1591+
PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
15761592
PyMem_DEL(dest);
15771593

15781594
return ret;

Modules/clinic/_winapi.c.h

Lines changed: 5 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)