Skip to content

Commit fdddd45

Browse files
Reject a NUL in complexstr()
A NUL cell ends a batch write and a cell array read (add_wchnstr(3X)), so addstr() would write only the cells before it and in_wchstr() would read only those, on both a wide and a narrow build. addstr() already rejects an embedded NUL in a str.
1 parent a4d2907 commit fdddd45

2 files changed

Lines changed: 15 additions & 7 deletions

File tree

Lib/test/test_curses.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,9 +1044,9 @@ def test_cell_null_char(self):
10441044
win = curses.newwin(3, 8, 0, 0)
10451045
win.insch(0, 0, '\0')
10461046
self.assertEqual(win.in_wch(0, 0), cell)
1047-
# complexstr() splits a NUL into a cell of its own.
1048-
self.assertEqual(len(curses.complexstr('a\0b')), 3)
1049-
self.assertEqual(curses.complexstr('\0')[0], cell)
1047+
# A string of cells cannot hold a NUL: it would end a batch write.
1048+
self.assertRaises(ValueError, curses.complexstr, 'a\0b')
1049+
self.assertRaises(ValueError, curses.complexstr, '\0')
10501050

10511051
def test_add_string_behavior(self):
10521052
# addstr() advances the cursor past the written text; addnstr()

Modules/_cursesmodule.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,16 @@ static PyObject *
13241324
complexstr_from_string(cursesmodule_state *state, PyObject *str,
13251325
attr_t attr, int pair)
13261326
{
1327+
/* A NUL cell ends a batch write and a cell array read (add_wchnstr(3X)),
1328+
so a string of cells cannot hold one, as addstr() cannot either. */
1329+
Py_ssize_t nul = PyUnicode_FindChar(str, 0, 0, PyUnicode_GET_LENGTH(str), 1);
1330+
if (nul < -1) {
1331+
return NULL;
1332+
}
1333+
if (nul >= 0) {
1334+
PyErr_SetString(PyExc_ValueError, "embedded null character");
1335+
return NULL;
1336+
}
13271337
#ifdef HAVE_NCURSESW
13281338
Py_ssize_t n;
13291339
wchar_t *wbuf = PyUnicode_AsWideCharString(str, &n);
@@ -1340,9 +1350,7 @@ complexstr_from_string(cursesmodule_state *state, PyObject *str,
13401350
wchar_t cell[CCHARW_MAX + 1];
13411351
Py_ssize_t k = 0;
13421352
cell[k++] = wbuf[i++];
1343-
while (i < n && k < CCHARW_MAX && wbuf[i] != L'\0' &&
1344-
wcwidth(wbuf[i]) == 0)
1345-
{
1353+
while (i < n && k < CCHARW_MAX && wcwidth(wbuf[i]) == 0) {
13461354
cell[k++] = wbuf[i++];
13471355
}
13481356
cell[k] = L'\0';
@@ -1351,7 +1359,7 @@ complexstr_from_string(cursesmodule_state *state, PyObject *str,
13511359
control character (wcwidth < 0) may stand alone but cannot carry
13521360
combining marks. */
13531361
int width = wcwidth(cell[0]);
1354-
if ((width == 0 && cell[0] != L'\0') || (k > 1 && width < 0)) {
1362+
if (width == 0 || (k > 1 && width < 0)) {
13551363
PyErr_Format(PyExc_ValueError,
13561364
"a character cell must be a single spacing character "
13571365
"optionally followed by up to %d combining characters",

0 commit comments

Comments
 (0)