Skip to content

Commit 90a186a

Browse files
committed
bpo-44172: Keep reference to original window in curses subwindow objects
The X/Open curses specification[0] and ncurses documentation[1] both state that subwindows must be deleted before the main window. Deleting the windows in the wrong order causes a double-free with NetBSD's curses implementation. To fix this, keep track of the original window object in the subwindow object, and keep a reference to the original for the lifetime of the subwindow. [0] https://pubs.opengroup.org/onlinepubs/7908799/xcurses/delwin.html [1] https://invisible-island.net/ncurses/man/curs_window.3x.html
1 parent 4fdcc39 commit 90a186a

3 files changed

Lines changed: 17 additions & 9 deletions

File tree

Include/py_curses.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@ extern "C" {
5858

5959
/* Type declarations */
6060

61-
typedef struct {
61+
typedef struct PyCursesWindowObject {
6262
PyObject_HEAD
6363
WINDOW *win;
6464
char *encoding;
65+
struct PyCursesWindowObject *orig;
6566
} PyCursesWindowObject;
6667

6768
#define PyCursesWindow_Check(v) Py_IS_TYPE(v, &PyCursesWindow_Type)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Keep a reference to original PyCursesWindowObject in subwindows so
2+
that the original WINDOW does not get deleted before the subwindow
3+
WINDOW.

Modules/_cursesmodule.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,8 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
663663
/* Allocation and deallocation of Window Objects */
664664

665665
static PyObject *
666-
PyCursesWindow_New(WINDOW *win, const char *encoding)
666+
PyCursesWindow_New(WINDOW *win, const char *encoding,
667+
PyCursesWindowObject *orig)
667668
{
668669
PyCursesWindowObject *wo;
669670

@@ -694,6 +695,8 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
694695
PyErr_NoMemory();
695696
return NULL;
696697
}
698+
wo->orig = orig;
699+
Py_XINCREF(orig);
697700
return (PyObject *)wo;
698701
}
699702

@@ -703,6 +706,7 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
703706
if (wo->win != stdscr) delwin(wo->win);
704707
if (wo->encoding != NULL)
705708
PyMem_Free(wo->encoding);
709+
Py_XDECREF(wo->orig);
706710
PyObject_Free(wo);
707711
}
708712

@@ -1304,7 +1308,7 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
13041308
return NULL;
13051309
}
13061310

1307-
return (PyObject *)PyCursesWindow_New(win, NULL);
1311+
return (PyObject *)PyCursesWindow_New(win, NULL, self);
13081312
}
13091313

13101314
/*[clinic input]
@@ -2332,7 +2336,7 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
23322336
return NULL;
23332337
}
23342338

2335-
return (PyObject *)PyCursesWindow_New(win, self->encoding);
2339+
return (PyObject *)PyCursesWindow_New(win, self->encoding, self);
23362340
}
23372341

23382342
/*[clinic input]
@@ -3081,7 +3085,7 @@ _curses_getwin(PyObject *module, PyObject *file)
30813085
PyErr_SetString(PyCursesError, catchall_NULL);
30823086
goto error;
30833087
}
3084-
res = PyCursesWindow_New(win, NULL);
3088+
res = PyCursesWindow_New(win, NULL, NULL);
30853089

30863090
error:
30873091
fclose(fp);
@@ -3254,7 +3258,7 @@ _curses_initscr_impl(PyObject *module)
32543258

32553259
if (initialised) {
32563260
wrefresh(stdscr);
3257-
return (PyObject *)PyCursesWindow_New(stdscr, NULL);
3261+
return (PyObject *)PyCursesWindow_New(stdscr, NULL, NULL);
32583262
}
32593263

32603264
win = initscr();
@@ -3346,7 +3350,7 @@ _curses_initscr_impl(PyObject *module)
33463350
SetDictInt("LINES", LINES);
33473351
SetDictInt("COLS", COLS);
33483352

3349-
winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
3353+
winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL, NULL);
33503354
screen_encoding = winobj->encoding;
33513355
return (PyObject *)winobj;
33523356
}
@@ -3719,7 +3723,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
37193723
return NULL;
37203724
}
37213725

3722-
return (PyObject *)PyCursesWindow_New(win, NULL);
3726+
return (PyObject *)PyCursesWindow_New(win, NULL, NULL);
37233727
}
37243728

37253729
/*[clinic input]
@@ -3758,7 +3762,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
37583762
return NULL;
37593763
}
37603764

3761-
return (PyObject *)PyCursesWindow_New(win, NULL);
3765+
return (PyObject *)PyCursesWindow_New(win, NULL, NULL);
37623766
}
37633767

37643768
/*[clinic input]

0 commit comments

Comments
 (0)