Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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
  • Loading branch information
michaelforney committed May 19, 2021
commit 90a186a65826bffbc46c95f9482a2fa625f59bd8
3 changes: 2 additions & 1 deletion Include/py_curses.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ extern "C" {

/* Type declarations */

typedef struct {
typedef struct PyCursesWindowObject {
PyObject_HEAD
WINDOW *win;
char *encoding;
struct PyCursesWindowObject *orig;
} PyCursesWindowObject;

#define PyCursesWindow_Check(v) Py_IS_TYPE(v, &PyCursesWindow_Type)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Keep a reference to original PyCursesWindowObject in subwindows so
that the original WINDOW does not get deleted before the subwindow
WINDOW.
20 changes: 12 additions & 8 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,8 @@ Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns")
/* Allocation and deallocation of Window Objects */

static PyObject *
PyCursesWindow_New(WINDOW *win, const char *encoding)
PyCursesWindow_New(WINDOW *win, const char *encoding,
PyCursesWindowObject *orig)
{
PyCursesWindowObject *wo;

Expand Down Expand Up @@ -694,6 +695,8 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
PyErr_NoMemory();
return NULL;
}
wo->orig = orig;
Py_XINCREF(orig);
return (PyObject *)wo;
}

Expand All @@ -703,6 +706,7 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
if (wo->win != stdscr) delwin(wo->win);
if (wo->encoding != NULL)
PyMem_Free(wo->encoding);
Py_XDECREF(wo->orig);
PyObject_Free(wo);
}

Expand Down Expand Up @@ -1304,7 +1308,7 @@ _curses_window_derwin_impl(PyCursesWindowObject *self, int group_left_1,
return NULL;
}

return (PyObject *)PyCursesWindow_New(win, NULL);
return (PyObject *)PyCursesWindow_New(win, NULL, self);
}

/*[clinic input]
Expand Down Expand Up @@ -2332,7 +2336,7 @@ _curses_window_subwin_impl(PyCursesWindowObject *self, int group_left_1,
return NULL;
}

return (PyObject *)PyCursesWindow_New(win, self->encoding);
return (PyObject *)PyCursesWindow_New(win, self->encoding, self);
}

/*[clinic input]
Expand Down Expand Up @@ -3081,7 +3085,7 @@ _curses_getwin(PyObject *module, PyObject *file)
PyErr_SetString(PyCursesError, catchall_NULL);
goto error;
}
res = PyCursesWindow_New(win, NULL);
res = PyCursesWindow_New(win, NULL, NULL);

error:
fclose(fp);
Expand Down Expand Up @@ -3254,7 +3258,7 @@ _curses_initscr_impl(PyObject *module)

if (initialised) {
wrefresh(stdscr);
return (PyObject *)PyCursesWindow_New(stdscr, NULL);
return (PyObject *)PyCursesWindow_New(stdscr, NULL, NULL);
}

win = initscr();
Expand Down Expand Up @@ -3346,7 +3350,7 @@ _curses_initscr_impl(PyObject *module)
SetDictInt("LINES", LINES);
SetDictInt("COLS", COLS);

winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL, NULL);
screen_encoding = winobj->encoding;
return (PyObject *)winobj;
}
Expand Down Expand Up @@ -3719,7 +3723,7 @@ _curses_newpad_impl(PyObject *module, int nlines, int ncols)
return NULL;
}

return (PyObject *)PyCursesWindow_New(win, NULL);
return (PyObject *)PyCursesWindow_New(win, NULL, NULL);
}

/*[clinic input]
Expand Down Expand Up @@ -3758,7 +3762,7 @@ _curses_newwin_impl(PyObject *module, int nlines, int ncols,
return NULL;
}

return (PyObject *)PyCursesWindow_New(win, NULL);
return (PyObject *)PyCursesWindow_New(win, NULL, NULL);
}

/*[clinic input]
Expand Down