https://github.com/python/cpython/commit/e7b21b66a4ddc0ed57f74972bfb7cf1b678fca0a commit: e7b21b66a4ddc0ed57f74972bfb7cf1b678fca0a branch: main author: Serhiy Storchaka <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-06-29T12:06:47Z summary:
gh-152503: Fix garbage text from curses wide-character cell reads (GH-152505) window.in_wch(), window.in_wchstr() and window.getbkgrnd() read a cell into an uninitialized cchar_t, relying on the curses library to leave the text NUL-terminated -- which ncurses does but X/Open does not require, so some libraries (such as NetBSD curses) returned uninitialized bytes as wide characters. Zero-initialize the cell buffers before the read and default the getcchar() output to an empty string. Co-authored-by: Claude Opus 4.8 <[email protected]> files: A Misc/NEWS.d/next/Library/2026-06-28-16-20-07.gh-issue-152503.N55ose.rst M Modules/_cursesmodule.c diff --git a/Misc/NEWS.d/next/Library/2026-06-28-16-20-07.gh-issue-152503.N55ose.rst b/Misc/NEWS.d/next/Library/2026-06-28-16-20-07.gh-issue-152503.N55ose.rst new file mode 100644 index 00000000000000..e97c5d74600c67 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-28-16-20-07.gh-issue-152503.N55ose.rst @@ -0,0 +1,4 @@ +Fix :meth:`curses.window.in_wch`, :meth:`curses.window.in_wchstr` and +:meth:`curses.window.getbkgrnd` returning garbage text when :mod:`curses` is +built against a curses library that does not NUL-terminate the ``cchar_t`` +text array (such as NetBSD curses). diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 4e7b27cdb7be6e..07883848992a20 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -765,6 +765,9 @@ static int curses_getcchar(const cchar_t *wcval, wchar_t *wstr, attr_t *attrs, int *pair) { short spair = 0; + /* getcchar() is not guaranteed to write the text of an empty cell, so make + the output an empty string by default. */ + wstr[0] = L'\0'; #if _NCURSES_EXTENDED_COLOR_FUNCS int rtn = getcchar(wcval, wstr, attrs, &spair, pair); #else @@ -3079,7 +3082,8 @@ _curses_window_in_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) /*[clinic end generated code: output=846ca8a82f2ecab4 input=a55dd215367dfbb1]*/ { - curses_cell_t wcval; + /* Zeroed so getcchar() sees a NUL-terminated text array on read. */ + curses_cell_t wcval = {0}; cursesmodule_state *state = get_cursesmodule_state_by_win(self); #ifdef HAVE_NCURSESW int rtn; @@ -3126,7 +3130,8 @@ static PyObject * _curses_window_getbkgrnd_impl(PyCursesWindowObject *self) /*[clinic end generated code: output=afec19cad00eff71 input=e06bf3d6bf90d2ec]*/ { - curses_cell_t wcval; + /* Zeroed so getcchar() sees a NUL-terminated text array on read. */ + curses_cell_t wcval = {0}; cursesmodule_state *state = get_cursesmodule_state_by_win(self); #ifdef HAVE_NCURSESW if (wgetbkgrnd(self->win, &wcval) == ERR) { @@ -3842,7 +3847,10 @@ PyCursesWindow_in_wchstr(PyObject *op, PyObject *args) n = Py_MIN(n, max_buf_size - 1); cursesmodule_state *state = get_cursesmodule_state_by_win(self); - curses_cell_t *buf = PyMem_New(curses_cell_t, n + 1); + /* Zero the cells: reading a cell back through getcchar() relies on the + cchar_t text array being NUL-terminated, which some curses libraries + only guarantee for the characters they actually write. */ + curses_cell_t *buf = PyMem_Calloc(n + 1, sizeof(curses_cell_t)); if (buf == NULL) { return PyErr_NoMemory(); } _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
