From ec254c5dfa8c99f1ec061b252d155386e93f19ef Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 12 Aug 2023 14:06:56 +0300 Subject: [PATCH] [3.11] gh-106844: Fix issues in _winapi.LCMapStringEx (GH-107832) (GH-107875) * 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. Now strings longer than 2**31-1 characters caused OverflowError. (cherry picked from commit 04cc01453db2f0af72a06440831637f8bf512daf) --- Lib/test/test_ntpath.py | 1 + ...-07-18-13-01-26.gh-issue-106844.mci4xO.rst | 1 + Modules/_winapi.c | 26 ++++++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-07-18-13-01-26.gh-issue-106844.mci4xO.rst diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 646e81d1e2fa9b..75e50d92ed1eb1 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -908,6 +908,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 00000000000000..11fca7e0452f40 --- /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 in :func:`!_winapi.LCMapStringEx` which affects :func:`ntpath.normcase`. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 5c61d99a837515..7fb1f2f561b0f9 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -1571,24 +1571,26 @@ _winapi_LCMapStringEx_impl(PyObject *module, PyObject *locale, DWORD flags, if (!locale_) { return NULL; } - Py_ssize_t srcLenAsSsize; - int srcLen; - wchar_t *src_ = PyUnicode_AsWideCharString(src, &srcLenAsSsize); + Py_ssize_t src_size; + wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size); if (!src_) { PyMem_Free(locale_); return NULL; } - srcLen = (int)srcLenAsSsize; - if (srcLen != srcLenAsSsize) { - srcLen = -1; + if (src_size > INT_MAX) { + PyMem_Free(locale_); + PyMem_Free(src_); + PyErr_SetString(PyExc_OverflowError, "input string is too long"); + return NULL; } - int dest_size = LCMapStringEx(locale_, flags, src_, srcLen, NULL, 0, + int dest_size = LCMapStringEx(locale_, flags, src_, (int)src_size, NULL, 0, NULL, NULL, 0); - if (dest_size == 0) { + if (dest_size <= 0) { + DWORD error = GetLastError(); PyMem_Free(locale_); PyMem_Free(src_); - return PyErr_SetFromWindowsErr(0); + return PyErr_SetFromWindowsErr(error); } wchar_t* dest = PyMem_NEW(wchar_t, dest_size); @@ -1598,9 +1600,9 @@ _winapi_LCMapStringEx_impl(PyObject *module, PyObject *locale, DWORD flags, return PyErr_NoMemory(); } - int nmapped = LCMapStringEx(locale_, flags, src_, srcLen, 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(locale_); PyMem_Free(src_); @@ -1608,9 +1610,9 @@ _winapi_LCMapStringEx_impl(PyObject *module, PyObject *locale, DWORD flags, return PyErr_SetFromWindowsErr(error); } - PyObject *ret = PyUnicode_FromWideChar(dest, dest_size); PyMem_Free(locale_); PyMem_Free(src_); + PyObject *ret = PyUnicode_FromWideChar(dest, nmapped); PyMem_DEL(dest); return ret;