serhiy-storchaka · GitHub

window.in_wch(), window.in_wchstr() and window.getbkgrnd() can return a complexchar whose text is garbage, usually surfacing as ValueError: character U+xxxxxxxx is not in range [U+0000; U+10ffff], when curses is built against a curses library whose cell-read functions don't NUL-terminate the cchar_t text array.

The module reads a cell into an uninitialized cchar_t (e.g. win_wch(win, &wcval)) then extracts the text with getcchar(). This relies on two behaviours ncurses happens to provide but X/Open doesn't require: that the read leaves the text array NUL-terminated, and that getcchar() writes the output text for an empty cell. NetBSD curses does neither — its read functions assume the caller zeroed the struct, and its getcchar() finds the text by scanning for L'\0' and writes nothing for an empty cell — so uninitialized bytes get interpreted as wide characters.

This doesn't reproduce on a stock ncursesw build; it's a latent bug that manifests with other backends (found testing against NetBSD curses), but the assumption is worth not depending on.

Fix:

  • Zero-initialize the cell buffers before the read: in_wch/getbkgrnd (curses_cell_t wcval = {0};) and in_wchstr (PyMem_NewPyMem_Calloc).
  • Default the getcchar() output to an empty string in the curses_getcchar() wrapper (wstr[0] = L'\0';), since getcchar() need not write the text of an empty cell.

Both are no-ops on ncurses; test_curses keeps passing and stays refleak-clean.

Linked PRs

Read the original on github.com ↗