summaryrefslogtreecommitdiffstats
path: root/Modules/_cursesmodule.c
diff options
context:
space:
mode:
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>2024-09-11 15:49:33 (GMT)
committerGitHub <noreply@github.com>2024-09-11 15:49:33 (GMT)
commit2938c3dec99390087490124c2ef50e1592671e72 (patch)
tree5b9a5f2a21a53f8e176d0a65eea8fe89b51e5985 /Modules/_cursesmodule.c
parentef05801ba0cbf090034df17e2a0420fb42c2d538 (diff)
downloadcpython-2938c3dec99390087490124c2ef50e1592671e72.zip
cpython-2938c3dec99390087490124c2ef50e1592671e72.tar.gz
cpython-2938c3dec99390087490124c2ef50e1592671e72.tar.bz2
gh-123290: fix reference leaks in the error-branches of `_cursesmodule.c` (#123953)
Diffstat (limited to 'Modules/_cursesmodule.c')
-rw-r--r--Modules/_cursesmodule.c358
1 files changed, 211 insertions, 147 deletions
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index b5854e8..1d36b40 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -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++;
+ 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++;
}
- *p2 = (char)0;
- } else
- key_n2 = key_n;
- SetDictInt(key_n2,key);
- if (key_n2 != key_n)
- PyMem_Free(key_n2);
+ 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);
}
+ SetDictInt("KEY_MIN", KEY_MIN);
+ SetDictInt("KEY_MAX", KEY_MAX);
+#undef SetDictInt
+ return 0;
+}
- if (PyModule_AddType(m, &PyCursesWindow_Type) < 0) {
- return NULL;
+PyMODINIT_FUNC
+PyInit__curses(void)
+{
+ // create the module
+ PyObject *mod = PyModule_Create(&_cursesmodule);
+ if (mod == NULL) {
+ goto error;
}
- return m;
+#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;
}