[Python-checkins] [3.12] gh-106844: Fix issues in _winapi.LCMapStringEx (GH-107832) (#107874)
Yhg1s
webhook-mailer at python.org
Wed Aug 16 06:10:46 EDT 2023
https://github.com/python/cpython/commit/b5176a86bd2587856f88aec3958ad8caef7b11fc
commit: b5176a86bd2587856f88aec3958ad8caef7b11fc
branch: 3.12
author: Serhiy Storchaka <storchaka at gmail.com>
committer: Yhg1s <thomas at python.org>
date: 2023-08-16T12:10:42+02:00
summary:
[3.12] gh-106844: Fix issues in _winapi.LCMapStringEx (GH-107832) (#107874)
* 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..
(cherry picked from commit 04cc01453db2f0af72a06440831637f8bf512daf)
files:
A Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst
M Lib/test/test_ntpath.py
M Modules/_winapi.c
M Modules/clinic/_winapi.c.h
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index 538d758624c9d..78e1cb582512b 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -1036,6 +1036,7 @@ def test_path_normcase(self):
self._check_function(self.path.normcase)
if sys.platform == 'win32':
self.assertEqual(ntpath.normcase('\u03a9\u2126'), 'ωΩ')
+ self.assertEqual(ntpath.normcase('abc\x00def'), 'abc\x00def')
def test_path_isabs(self):
self._check_function(self.path.isabs)
diff --git a/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst
new file mode 100644
index 0000000000000..1fdf162ef4ecd
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst
@@ -0,0 +1 @@
+Fix integer overflow and truncating by the null character in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`.
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index d6d2f4a6a9b10..77275408aed86 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -1538,40 +1538,56 @@ _winapi.LCMapStringEx
locale: LPCWSTR
flags: DWORD
- src: LPCWSTR
+ src: unicode
[clinic start generated code]*/
static PyObject *
_winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
- LPCWSTR src)
-/*[clinic end generated code: output=cf4713d80e2b47c9 input=9fe26f95d5ab0001]*/
+ PyObject *src)
+/*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/
{
if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
LCMAP_SORTKEY)) {
return PyErr_Format(PyExc_ValueError, "unsupported flags");
}
- int dest_size = LCMapStringEx(locale, flags, src, -1, NULL, 0,
+ Py_ssize_t src_size;
+ wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
+ if (!src_) {
+ return NULL;
+ }
+ if (src_size > INT_MAX) {
+ PyMem_Free(src_);
+ PyErr_SetString(PyExc_OverflowError, "input string is too long");
+ return NULL;
+ }
+
+ int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0,
NULL, NULL, 0);
- if (dest_size == 0) {
- return PyErr_SetFromWindowsErr(0);
+ if (dest_size <= 0) {
+ DWORD error = GetLastError();
+ PyMem_Free(src_);
+ return PyErr_SetFromWindowsErr(error);
}
wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
if (dest == NULL) {
+ PyMem_Free(src_);
return PyErr_NoMemory();
}
- int nmapped = LCMapStringEx(locale, flags, src, -1, dest, dest_size,
+ int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size,
NULL, NULL, 0);
- if (nmapped == 0) {
+ if (nmapped <= 0) {
DWORD error = GetLastError();
+ PyMem_Free(src_);
PyMem_DEL(dest);
return PyErr_SetFromWindowsErr(error);
}
- PyObject *ret = PyUnicode_FromWideChar(dest, dest_size - 1);
+ PyMem_Free(src_);
+ PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
PyMem_DEL(dest);
return ret;
diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h
index 3767b19d76db0..1394a8fcffd9f 100644
--- a/Modules/clinic/_winapi.c.h
+++ b/Modules/clinic/_winapi.c.h
@@ -885,7 +885,7 @@ PyDoc_STRVAR(_winapi_LCMapStringEx__doc__,
static PyObject *
_winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
- LPCWSTR src);
+ PyObject *src);
static PyObject *
_winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -912,16 +912,16 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
static const char * const _keywords[] = {"locale", "flags", "src", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
- .format = "O&kO&:LCMapStringEx",
+ .format = "O&kU:LCMapStringEx",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
LPCWSTR locale = NULL;
DWORD flags;
- LPCWSTR src = NULL;
+ PyObject *src;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
- _PyUnicode_WideCharString_Converter, &locale, &flags, _PyUnicode_WideCharString_Converter, &src)) {
+ _PyUnicode_WideCharString_Converter, &locale, &flags, &src)) {
goto exit;
}
return_value = _winapi_LCMapStringEx_impl(module, locale, flags, src);
@@ -929,8 +929,6 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
exit:
/* Cleanup for locale */
PyMem_Free((void *)locale);
- /* Cleanup for src */
- PyMem_Free((void *)src);
return return_value;
}
@@ -1481,4 +1479,4 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO
return return_value;
}
-/*[clinic end generated code: output=be1343b3759e0c96 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=9d43ae4bdbe1126a input=a9049054013a1b77]*/
More information about the Python-checkins
mailing list