From 7ef0e3204040eeb13e6e6f0833cf91f2f78c2af5 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Mon, 27 Jul 2026 22:03:38 +0300 Subject: [PATCH 1/2] gh-154781: Zero the in_wstr() buffer in curses winnwstr() only writes the terminating null when it stored at least one character, so with n of 0 the result was read from uninitialized memory. Use PyMem_Calloc, like in_wchstr() already does. --- Lib/test/test_curses.py | 6 ++++++ Modules/_cursesmodule.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 31b7371abd3230..82bb10ad58c635 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -514,6 +514,12 @@ def test_in_wstr(self): self.assertEqual(stdscr.in_wstr(0, 0, len(s)), s) self.assertIsInstance(stdscr.instr(0, 0, len(s)), bytes) + # Reading no characters gives an empty string, like instr() and + # in_wchstr() do. curses does not terminate the buffer in this case. + stdscr.addstr(0, 0, 'abz') + self.assertEqual(stdscr.in_wstr(0, 0, 0), '') + self.assertEqual(stdscr.in_wstr(0), '') + def test_complexchar(self): # A complexchar is a styled wide-character cell: str() is its text, # and the attr and pair attributes are its rendition. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 2b580c3475e6d9..1ad7358dfa5e36 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3850,7 +3850,9 @@ PyCursesWindow_in_wstr(PyObject *op, PyObject *args) } n = Py_MIN(n, max_buf_size - 1); - wchar_t *buf = PyMem_New(wchar_t, n + 1); + /* Zero the buffer: winnwstr() only writes the terminating null when it + stored at least one character, and the result is read up to it. */ + wchar_t *buf = PyMem_Calloc(n + 1, sizeof(wchar_t)); if (buf == NULL) { return PyErr_NoMemory(); } From 28d971da830cf8913317aef52cf672d3edd92d20 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Mon, 27 Jul 2026 22:57:39 +0300 Subject: [PATCH 2/2] remove comment --- Modules/_cursesmodule.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 1ad7358dfa5e36..7d794b879e34ff 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3850,8 +3850,6 @@ PyCursesWindow_in_wstr(PyObject *op, PyObject *args) } n = Py_MIN(n, max_buf_size - 1); - /* Zero the buffer: winnwstr() only writes the terminating null when it - stored at least one character, and the result is read up to it. */ wchar_t *buf = PyMem_Calloc(n + 1, sizeof(wchar_t)); if (buf == NULL) { return PyErr_NoMemory();