gh-123290: fix reference leaks in the error-branches of `_cursesmodule.c` (#123953)

This commit is contained in:
Bénédikt Tran 2024-09-11 17:49:33 +02:00 committed by GitHub
parent ef05801ba0
commit 2938c3dec9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 214 additions and 150 deletions

View File

@ -716,9 +716,13 @@ PyCursesWindow_New(WINDOW *win, const char *encoding)
static void
PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
{
if (wo->win != stdscr) delwin(wo->win);
if (wo->encoding != NULL)
if (wo->win != stdscr && wo->win != NULL) {
// silently ignore errors in delwin(3)
(void)delwin(wo->win);
}
if (wo->encoding != NULL) {
PyMem_Free(wo->encoding);
}
PyObject_Free(wo);
}
@ -3266,7 +3270,6 @@ _curses_initscr_impl(PyObject *module)
/*[clinic end generated code: output=619fb68443810b7b input=514f4bce1821f6b5]*/
{
WINDOW *win;
PyCursesWindowObject *winobj;
if (initialised) {
wrefresh(stdscr);
@ -3284,12 +3287,17 @@ _curses_initscr_impl(PyObject *module)
/* This was moved from initcurses() because it core dumped on SGI,
where they're not defined until you've called initscr() */
#define SetDictInt(string,ch) \
do { \
PyObject *o = PyLong_FromLong((long) (ch)); \
if (o && PyDict_SetItemString(ModDict, string, o) == 0) { \
Py_DECREF(o); \
} \
#define SetDictInt(NAME, VALUE) \
do { \
PyObject *value = PyLong_FromLong((long)(VALUE)); \
if (value == NULL) { \
return NULL; \
} \
int rc = PyDict_SetItemString(ModDict, (NAME), value); \
Py_DECREF(value); \
if (rc < 0) { \
return NULL; \
} \
} while (0)
/* Here are some graphic symbols you can use */
@ -3361,8 +3369,12 @@ _curses_initscr_impl(PyObject *module)
SetDictInt("LINES", LINES);
SetDictInt("COLS", COLS);
#undef SetDictInt
winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
PyCursesWindowObject *winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL);
if (winobj == NULL) {
return NULL;
}
screen_encoding = winobj->encoding;
return (PyObject *)winobj;
}
@ -3970,46 +3982,47 @@ _curses_qiflush_impl(PyObject *module, int flag)
static int
update_lines_cols(void)
{
PyObject *o;
PyObject *m = PyImport_ImportModule("curses");
PyObject *exposed_module = NULL, *o = NULL;
if (!m)
return 0;
exposed_module = PyImport_ImportModule("curses");
if (exposed_module == NULL) {
goto error;
}
PyObject *exposed_module_dict = PyModule_GetDict(exposed_module); // borrowed
if (exposed_module_dict == NULL) {
goto error;
}
o = PyLong_FromLong(LINES);
if (!o) {
Py_DECREF(m);
return 0;
if (o == NULL) {
goto error;
}
if (PyObject_SetAttrString(m, "LINES", o)) {
Py_DECREF(m);
Py_DECREF(o);
return 0;
if (PyDict_SetItemString(exposed_module_dict, "LINES", o) < 0) {
goto error;
}
if (PyDict_SetItemString(ModDict, "LINES", o)) {
Py_DECREF(m);
Py_DECREF(o);
return 0;
if (PyDict_SetItemString(ModDict, "LINES", o) < 0) {
goto error;
}
Py_DECREF(o);
o = PyLong_FromLong(COLS);
if (!o) {
Py_DECREF(m);
return 0;
if (o == NULL) {
goto error;
}
if (PyObject_SetAttrString(m, "COLS", o)) {
Py_DECREF(m);
Py_DECREF(o);
return 0;
if (PyDict_SetItemString(exposed_module_dict, "COLS", o) < 0) {
goto error;
}
if (PyDict_SetItemString(ModDict, "COLS", o)) {
Py_DECREF(m);
Py_DECREF(o);
return 0;
if (PyDict_SetItemString(ModDict, "COLS", o) < 0) {
goto error;
}
Py_DECREF(o);
Py_DECREF(m);
Py_DECREF(exposed_module);
return 1;
error:
Py_XDECREF(o);
Py_DECREF(exposed_module);
return 0;
}
/*[clinic input]
@ -4210,35 +4223,33 @@ static PyObject *
_curses_start_color_impl(PyObject *module)
/*[clinic end generated code: output=8b772b41d8090ede input=0ca0ecb2b77e1a12]*/
{
int code;
PyObject *c, *cp;
PyCursesInitialised;
code = start_color();
if (code != ERR) {
initialisedcolors = TRUE;
c = PyLong_FromLong((long) COLORS);
if (c == NULL)
return NULL;
if (PyDict_SetItemString(ModDict, "COLORS", c) < 0) {
Py_DECREF(c);
return NULL;
}
Py_DECREF(c);
cp = PyLong_FromLong((long) COLOR_PAIRS);
if (cp == NULL)
return NULL;
if (PyDict_SetItemString(ModDict, "COLOR_PAIRS", cp) < 0) {
Py_DECREF(cp);
return NULL;
}
Py_DECREF(cp);
Py_RETURN_NONE;
} else {
if (start_color() == ERR) {
PyErr_SetString(PyCursesError, "start_color() returned ERR");
return NULL;
}
initialisedcolors = TRUE;
#define DICT_ADD_INT_VALUE(NAME, VALUE) \
do { \
PyObject *value = PyLong_FromLong((long)(VALUE)); \
if (value == NULL) { \
return NULL; \
} \
int rc = PyDict_SetItemString(ModDict, (NAME), value); \
Py_DECREF(value); \
if (rc < 0) { \
return NULL; \
} \
} while (0)
DICT_ADD_INT_VALUE("COLORS", COLORS);
DICT_ADD_INT_VALUE("COLOR_PAIRS", COLOR_PAIRS);
#undef DICT_ADD_INT_VALUE
Py_RETURN_NONE;
}
/*[clinic input]
@ -4595,10 +4606,7 @@ static PyStructSequence_Desc ncurses_version_desc = {
static PyObject *
make_ncurses_version(PyTypeObject *type)
{
PyObject *ncurses_version;
int pos = 0;
ncurses_version = PyStructSequence_New(type);
PyObject *ncurses_version = PyStructSequence_New(type);
if (ncurses_version == NULL) {
return NULL;
}
@ -4610,18 +4618,20 @@ make_ncurses_version(PyTypeObject *type)
minor = NCURSES_VERSION_MINOR;
patch = NCURSES_VERSION_PATCH;
}
#define SetIntItem(flag) \
PyStructSequence_SET_ITEM(ncurses_version, pos++, PyLong_FromLong(flag)); \
if (PyErr_Occurred()) { \
Py_CLEAR(ncurses_version); \
return NULL; \
}
SetIntItem(major)
SetIntItem(minor)
SetIntItem(patch)
#undef SetIntItem
#define SET_VERSION_COMPONENT(INDEX, VALUE) \
do { \
PyObject *o = PyLong_FromLong(VALUE); \
if (o == NULL) { \
Py_DECREF(ncurses_version); \
return NULL; \
} \
PyStructSequence_SET_ITEM(ncurses_version, INDEX, o); \
} while (0)
SET_VERSION_COMPONENT(0, major);
SET_VERSION_COMPONENT(1, minor);
SET_VERSION_COMPONENT(2, patch);
#undef SET_VERSION_COMPONENT
return ncurses_version;
}
@ -4753,33 +4763,28 @@ curses_destructor(PyObject *op)
PyMem_Free(ptr);
}
PyMODINIT_FUNC
PyInit__curses(void)
static int
cursesmodule_exec(PyObject *module)
{
PyObject *m, *d, *v, *c_api_object;
/* Initialize object type */
if (PyType_Ready(&PyCursesWindow_Type) < 0)
return NULL;
/* Create the module and add the functions */
m = PyModule_Create(&_cursesmodule);
if (m == NULL)
return NULL;
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
if (PyType_Ready(&PyCursesWindow_Type) < 0) {
return -1;
}
if (PyModule_AddType(module, &PyCursesWindow_Type) < 0) {
return -1;
}
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
if (d == NULL)
return NULL;
ModDict = d; /* For PyCurses_InitScr to use later */
PyObject *module_dict = PyModule_GetDict(module);
if (module_dict == NULL) {
return -1;
}
ModDict = module_dict; /* For PyCurses_InitScr to use later */
void **PyCurses_API = PyMem_Calloc(PyCurses_API_pointers, sizeof(void *));
if (PyCurses_API == NULL) {
PyErr_NoMemory();
return NULL;
return -1;
}
/* Initialize the C API pointer array */
PyCurses_API[0] = (void *)Py_NewRef(&PyCursesWindow_Type);
@ -4788,28 +4793,45 @@ PyInit__curses(void)
PyCurses_API[3] = (void *)func_PyCursesInitialisedColor;
/* Add a capsule for the C API */
c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME,
curses_destructor);
PyObject *c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME,
curses_destructor);
if (c_api_object == NULL) {
Py_DECREF(PyCurses_API[0]);
PyMem_Free(PyCurses_API);
return NULL;
}
if (PyDict_SetItemString(d, "_C_API", c_api_object) < 0) {
Py_DECREF(c_api_object);
return NULL;
return -1;
}
int rc = PyDict_SetItemString(module_dict, "_C_API", c_api_object);
Py_DECREF(c_api_object);
if (rc < 0) {
return -1;
}
/* For exception curses.error */
PyCursesError = PyErr_NewException("_curses.error", NULL, NULL);
PyDict_SetItemString(d, "error", PyCursesError);
if (PyCursesError == NULL) {
return -1;
}
rc = PyDict_SetItemString(module_dict, "error", PyCursesError);
Py_DECREF(PyCursesError);
if (rc < 0) {
return -1;
}
/* Make the version available */
v = PyBytes_FromString(PyCursesVersion);
PyDict_SetItemString(d, "version", v);
PyDict_SetItemString(d, "__version__", v);
Py_DECREF(v);
PyObject *curses_version = PyBytes_FromString(PyCursesVersion);
if (curses_version == NULL) {
return -1;
}
rc = PyDict_SetItemString(module_dict, "version", curses_version);
if (rc < 0) {
Py_DECREF(curses_version);
return -1;
}
rc = PyDict_SetItemString(module_dict, "__version__", curses_version);
Py_CLEAR(curses_version);
if (rc < 0) {
return -1;
}
#ifdef NCURSES_VERSION
/* ncurses_version */
@ -4817,17 +4839,33 @@ PyInit__curses(void)
version_type = _PyStructSequence_NewType(&ncurses_version_desc,
Py_TPFLAGS_DISALLOW_INSTANTIATION);
if (version_type == NULL) {
return NULL;
return -1;
}
v = make_ncurses_version(version_type);
PyObject *ncurses_version = make_ncurses_version(version_type);
Py_DECREF(version_type);
if (v == NULL) {
return NULL;
if (ncurses_version == NULL) {
return -1;
}
rc = PyDict_SetItemString(module_dict, "ncurses_version", ncurses_version);
Py_CLEAR(ncurses_version);
if (rc < 0) {
return -1;
}
PyDict_SetItemString(d, "ncurses_version", v);
Py_DECREF(v);
#endif /* NCURSES_VERSION */
#define SetDictInt(NAME, VALUE) \
do { \
PyObject *value = PyLong_FromLong((long)(VALUE)); \
if (value == NULL) { \
return -1; \
} \
int rc = PyDict_SetItemString(module_dict, (NAME), value); \
Py_DECREF(value); \
if (rc < 0) { \
return -1; \
} \
} while (0)
SetDictInt("ERR", ERR);
SetDictInt("OK", OK);
@ -4923,43 +4961,69 @@ PyInit__curses(void)
SetDictInt("REPORT_MOUSE_POSITION", REPORT_MOUSE_POSITION);
#endif
/* Now set everything up for KEY_ variables */
{
int key;
char *key_n;
char *key_n2;
for (key=KEY_MIN;key < KEY_MAX; key++) {
key_n = (char *)keyname(key);
if (key_n == NULL || strcmp(key_n,"UNKNOWN KEY")==0)
continue;
if (strncmp(key_n,"KEY_F(",6)==0) {
char *p1, *p2;
key_n2 = PyMem_Malloc(strlen(key_n)+1);
if (!key_n2) {
PyErr_NoMemory();
break;
}
p1 = key_n;
p2 = key_n2;
while (*p1) {
if (*p1 != '(' && *p1 != ')') {
*p2 = *p1;
p2++;
}
p1++;
}
*p2 = (char)0;
} else
key_n2 = key_n;
SetDictInt(key_n2,key);
if (key_n2 != key_n)
PyMem_Free(key_n2);
for (int keycode = KEY_MIN; keycode < KEY_MAX; keycode++) {
const char *key_name = keyname(keycode);
if (key_name == NULL || strcmp(key_name, "UNKNOWN KEY") == 0) {
continue;
}
if (strncmp(key_name, "KEY_F(", 6) == 0) {
char *fn_key_name = PyMem_Malloc(strlen(key_name) + 1);
if (!fn_key_name) {
PyErr_NoMemory();
return -1;
}
const char *p1 = key_name;
char *p2 = fn_key_name;
while (*p1) {
if (*p1 != '(' && *p1 != ')') {
*p2 = *p1;
p2++;
}
p1++;
}
*p2 = (char)0;
PyObject *p_keycode = PyLong_FromLong((long)keycode);
if (p_keycode == NULL) {
PyMem_Free(fn_key_name);
return -1;
}
int rc = PyDict_SetItemString(module_dict, fn_key_name, p_keycode);
Py_DECREF(p_keycode);
PyMem_Free(fn_key_name);
if (rc < 0) {
return -1;
}
}
else {
SetDictInt(key_name, keycode);
}
SetDictInt("KEY_MIN", KEY_MIN);
SetDictInt("KEY_MAX", KEY_MAX);
}
if (PyModule_AddType(m, &PyCursesWindow_Type) < 0) {
return NULL;
}
return m;
SetDictInt("KEY_MIN", KEY_MIN);
SetDictInt("KEY_MAX", KEY_MAX);
#undef SetDictInt
return 0;
}
PyMODINIT_FUNC
PyInit__curses(void)
{
// create the module
PyObject *mod = PyModule_Create(&_cursesmodule);
if (mod == NULL) {
goto error;
}
#ifdef Py_GIL_DISABLED
if (PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED) < 0) {
goto error;
}
#endif
// populate the module
if (cursesmodule_exec(mod) < 0) {
goto error;
}
return mod;
error:
Py_XDECREF(mod);
return NULL;
}