Skip to content

Commit 23180c5

Browse files
authored
gh-156953: Fix a reference leak in curses window.insnstr() (GH-156954)
insnstr() did not release the bytes object it converted its argument to when setting the attributes failed, unlike addstr(), addnstr() and insstr().
1 parent 23525c9 commit 23180c5

2 files changed

Lines changed: 18 additions & 0 deletions

File tree

Lib/test/test_curses.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3386,6 +3386,23 @@ def test_close(self):
33863386
# close() is idempotent.
33873387
screen.close()
33883388

3389+
def test_close_then_write_with_attr_keeps_no_reference(self):
3390+
# A write with an *attr* argument on a detached window fails while
3391+
# setting the rendition, and has to release the bytes it converted.
3392+
s = self.make_pty()
3393+
screen = curses.newterm('xterm', s, s)
3394+
win = screen.stdscr
3395+
screen.close()
3396+
writes = [lambda b: win.addstr(b, curses.A_BOLD),
3397+
lambda b: win.addnstr(b, 4, curses.A_BOLD),
3398+
lambda b: win.insstr(b, curses.A_BOLD),
3399+
lambda b: win.insnstr(b, 4, curses.A_BOLD)]
3400+
data = b'x' * 8
3401+
nrefs = sys.getrefcount(data)
3402+
for write in writes:
3403+
self.assertRaises(curses.error, write, data)
3404+
self.assertEqual(sys.getrefcount(data), nrefs)
3405+
33893406
@requires_curses_func('panel')
33903407
def test_close_then_panel_replace(self):
33913408
# A detached window has no underlying curses window, so replace()

Modules/_cursesmodule.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4364,6 +4364,7 @@ _curses_window_insnstr_impl(PyCursesWindowObject *self, int group_left_1,
43644364
curses_wattrset(self, attr, "insnstr") < 0)
43654365
{
43664366
curses_release_wstr(strtype, wstr);
4367+
Py_XDECREF(bytesobj);
43674368
return NULL;
43684369
}
43694370
}

0 commit comments

Comments
 (0)