diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index b5854e8c33f28a..c9900b7c247ae0 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -170,34 +170,71 @@ class _curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" static PyObject *PyCursesError; /* Tells whether setupterm() has been called to initialise terminfo. */ -static int initialised_setupterm = FALSE; +static int CURSES_SETUPTERM_CALLED = FALSE; /* Tells whether initscr() has been called to initialise curses. */ -static int initialised = FALSE; +static int CURSES_INITSCR_CALLED = FALSE; /* Tells whether start_color() has been called to initialise color usage. */ -static int initialisedcolors = FALSE; +static int CURSES_INITIALISED_COLORS = FALSE; -static char *screen_encoding = NULL; +static char *CURSES_SCREEN_ENCODING = NULL; /* Utility Macros */ -#define PyCursesSetupTermCalled \ - if (initialised_setupterm != TRUE) { \ - PyErr_SetString(PyCursesError, \ - "must call (at least) setupterm() first"); \ - return 0; } - -#define PyCursesInitialised \ - if (initialised != TRUE) { \ - PyErr_SetString(PyCursesError, \ - "must call initscr() first"); \ - return 0; } - -#define PyCursesInitialisedColor \ - if (initialisedcolors != TRUE) { \ - PyErr_SetString(PyCursesError, \ - "must call start_color() first"); \ - return 0; } + +/* + * Check that GLOBAL_FLAG is set, or advise to call FUNC_TO_CALL(). + * + * This macro returns 0 on error so that it can be used both in a + * boolean context and in a function that returns a (PyObject *). + */ +#define CHECK_STATE_FLAG(FUNC_TO_CALL, GLOBAL_FLAG) \ + do { \ + if ((GLOBAL_FLAG) != TRUE) { \ + assert(PyCursesError != NULL); \ + PyErr_SetString(PyCursesError, \ + "must call " FUNC_TO_CALL "() first"); \ + return 0; \ + } \ + } while (0) + +#define PyCursesSetupTermCalled \ + CHECK_STATE_FLAG("setupterm", CURSES_SETUPTERM_CALLED) + +#define PyCursesInitialised \ + CHECK_STATE_FLAG("initscr", CURSES_INITSCR_CALLED) + +#define PyCursesInitialisedColor \ + CHECK_STATE_FLAG("start_color", CURSES_INITIALISED_COLORS) + +/* Jump to the 'error' label if STATUS < 0. */ +#define CHECK_RET_CODE(STATUS) \ + do { \ + if ((STATUS) < 0) { \ + assert(PyErr_Occurred()); \ + goto error; \ + } \ + } while (0) + +/* + * Equivalent to DICT[NAME] = VALUE; on error, jump to the 'error' label. + * + * Parameters + * + * PyObject * DICT The Python dict to alter. + * const char * NAME The constant name. + * int or long VALUE The constant value. + */ +#define DICT_ADD_INT_VALUE(DICT, NAME, VALUE) \ + do { \ + PyObject *value = PyLong_FromLong((long)(VALUE)); \ + if (value == NULL) { \ + goto error; \ + } \ + int rc = PyDict_SetItemString((DICT), (NAME), value); \ + Py_DECREF(value); \ + CHECK_RET_CODE(rc); \ + } while (0) /* Utility Functions */ @@ -258,7 +295,7 @@ PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch) if (win) encoding = win->encoding; else - encoding = screen_encoding; + encoding = CURSES_SCREEN_ENCODING; bytes = PyUnicode_AsEncodedString(obj, encoding, NULL); if (bytes == NULL) return 0; @@ -716,9 +753,14 @@ 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) { + // Silently ignore errors in delwin(3) (e.g., passing + // a NULL pointer results in delwin() returning ERR). + (void)delwin(wo->win); + } + if (wo->encoding != NULL) { PyMem_Free(wo->encoding); + } PyObject_Free(wo); } @@ -2629,12 +2671,12 @@ PyTypeObject PyCursesWindow_Type = { #define NoArgNoReturnFunctionBody(X) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ return PyCursesCheckERR(X(), # X); } #define NoArgOrFlagNoReturnFunctionBody(X, flag) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ if (flag) \ return PyCursesCheckERR(X(), # X); \ else \ @@ -2643,23 +2685,23 @@ PyTypeObject PyCursesWindow_Type = { #define NoArgReturnIntFunctionBody(X) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ return PyLong_FromLong((long) X()); } #define NoArgReturnStringFunctionBody(X) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ return PyBytes_FromString(X()); } #define NoArgTrueFalseFunctionBody(X) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ return PyBool_FromLong(X()); } #define NoArgNoReturnVoidFunctionBody(X) \ { \ - PyCursesInitialised \ + PyCursesInitialised; \ X(); \ Py_RETURN_NONE; } @@ -3251,8 +3293,6 @@ _curses_init_pair_impl(PyObject *module, int pair_number, int fg, int bg) Py_RETURN_NONE; } -static PyObject *ModDict; - /*[clinic input] _curses.initscr @@ -3265,34 +3305,30 @@ static PyObject * _curses_initscr_impl(PyObject *module) /*[clinic end generated code: output=619fb68443810b7b input=514f4bce1821f6b5]*/ { - WINDOW *win; - PyCursesWindowObject *winobj; - - if (initialised) { + if (CURSES_INITSCR_CALLED) { wrefresh(stdscr); return (PyObject *)PyCursesWindow_New(stdscr, NULL); } - win = initscr(); + WINDOW *win = initscr(); if (win == NULL) { PyErr_SetString(PyCursesError, catchall_NULL); return NULL; } - initialised = initialised_setupterm = TRUE; + CURSES_INITSCR_CALLED = CURSES_SETUPTERM_CALLED = TRUE; /* 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); \ - } \ - } while (0) /* Here are some graphic symbols you can use */ + PyObject *module_dict = PyModule_GetDict(module); + if (module_dict == NULL) { + goto error; + } +#define SetDictInt(NAME, VALUE) DICT_ADD_INT_VALUE(module_dict, (NAME), (VALUE)) + SetDictInt("ACS_ULCORNER", (ACS_ULCORNER)); SetDictInt("ACS_LLCORNER", (ACS_LLCORNER)); SetDictInt("ACS_URCORNER", (ACS_URCORNER)); @@ -3361,10 +3397,17 @@ _curses_initscr_impl(PyObject *module) SetDictInt("LINES", LINES); SetDictInt("COLS", COLS); +#undef SetDictInt - winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); - screen_encoding = winobj->encoding; + PyCursesWindowObject *winobj = (PyCursesWindowObject *)PyCursesWindow_New(win, NULL); + if (winobj == NULL) { + goto error; + } + CURSES_SCREEN_ENCODING = winobj->encoding; return (PyObject *)winobj; + +error: + return NULL; } /*[clinic input] @@ -3405,7 +3448,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) } } - if (!initialised_setupterm && setupterm((char *)term, fd, &err) == ERR) { + if (!CURSES_SETUPTERM_CALLED && setupterm((char *)term, fd, &err) == ERR) { const char* s = "setupterm: unknown error"; if (err == 0) { @@ -3418,7 +3461,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) return NULL; } - initialised_setupterm = TRUE; + CURSES_SETUPTERM_CALLED = TRUE; Py_RETURN_NONE; } @@ -3967,49 +4010,32 @@ _curses_qiflush_impl(PyObject *module, int flag) /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES * and _curses.COLS */ #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM) -static int -update_lines_cols(void) +static int /* 1 on success, 0 on failure */ +update_lines_cols(PyObject *private_module) { - PyObject *o; - PyObject *m = PyImport_ImportModule("curses"); - - if (!m) - return 0; - - o = PyLong_FromLong(LINES); - if (!o) { - Py_DECREF(m); - return 0; - } - if (PyObject_SetAttrString(m, "LINES", o)) { - Py_DECREF(m); - Py_DECREF(o); + PyObject *exposed_module = PyImport_ImportModule("curses"); + if (exposed_module == NULL) { return 0; } - if (PyDict_SetItemString(ModDict, "LINES", o)) { - Py_DECREF(m); - Py_DECREF(o); - return 0; - } - Py_DECREF(o); - o = PyLong_FromLong(COLS); - if (!o) { - Py_DECREF(m); - return 0; - } - if (PyObject_SetAttrString(m, "COLS", o)) { - Py_DECREF(m); - Py_DECREF(o); - return 0; - } - if (PyDict_SetItemString(ModDict, "COLS", o)) { - Py_DECREF(m); - Py_DECREF(o); - return 0; - } - Py_DECREF(o); - Py_DECREF(m); +#define MODULE_ADD_INT_CONSTANT(MODULE, NAME, VALUE) \ + do { \ + if (PyModule_AddIntConstant((MODULE), (NAME), (long)(VALUE)) < 0) { \ + goto error; \ + } \ + } while (0) + + MODULE_ADD_INT_CONSTANT(exposed_module, "LINES", LINES); + MODULE_ADD_INT_CONSTANT(private_module, "LINES", LINES); + MODULE_ADD_INT_CONSTANT(exposed_module, "COLS", COLS); + MODULE_ADD_INT_CONSTANT(private_module, "COLS", COLS); +#undef MODULE_ADD_INT_CONSTANT + + Py_DECREF(exposed_module); return 1; + +error: + Py_XDECREF(exposed_module); + return 0; } /*[clinic input] @@ -4021,7 +4047,7 @@ static PyObject * _curses_update_lines_cols_impl(PyObject *module) /*[clinic end generated code: output=423f2b1e63ed0f75 input=5f065ab7a28a5d90]*/ { - if (!update_lines_cols()) { + if (!update_lines_cols(module)) { return NULL; } Py_RETURN_NONE; @@ -4108,7 +4134,7 @@ _curses_resizeterm_impl(PyObject *module, int nlines, int ncols) result = PyCursesCheckERR(resizeterm(nlines, ncols), "resizeterm"); if (!result) return NULL; - if (!update_lines_cols()) { + if (!update_lines_cols(module)) { Py_DECREF(result); return NULL; } @@ -4147,7 +4173,7 @@ _curses_resize_term_impl(PyObject *module, int nlines, int ncols) result = PyCursesCheckERR(resize_term(nlines, ncols), "resize_term"); if (!result) return NULL; - if (!update_lines_cols()) { + if (!update_lines_cols(module)) { Py_DECREF(result); return NULL; } @@ -4210,35 +4236,25 @@ 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); + if (start_color() != ERR) { + CURSES_INITIALISED_COLORS = TRUE; + PyObject *module_dict = PyModule_GetDict(module); + if (module_dict == NULL) { 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); + DICT_ADD_INT_VALUE(module_dict, "COLORS", COLORS); + DICT_ADD_INT_VALUE(module_dict, "COLOR_PAIRS", COLOR_PAIRS); Py_RETURN_NONE; - } else { + } + else { PyErr_SetString(PyCursesError, "start_color() returned ERR"); return NULL; } + +error: + return NULL; } /*[clinic input] @@ -4595,10 +4611,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,19 +4623,24 @@ 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) { \ + goto error; \ + } \ + 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; + +error: + Py_DECREF(ncurses_version); + return NULL; } #endif /* NCURSES_VERSION */ @@ -4756,30 +4774,30 @@ curses_destructor(PyObject *op) PyMODINIT_FUNC PyInit__curses(void) { - PyObject *m, *d, *v, *c_api_object; + PyObject *mod = NULL; /* Initialize object type */ - if (PyType_Ready(&PyCursesWindow_Type) < 0) - return NULL; + CHECK_RET_CODE(PyType_Ready(&PyCursesWindow_Type)); /* Create the module and add the functions */ - m = PyModule_Create(&_cursesmodule); - if (m == NULL) - return NULL; + mod = PyModule_Create(&_cursesmodule); + if (mod == NULL) { + goto error; + } #ifdef Py_GIL_DISABLED - PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); + CHECK_RET_CODE(PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED)); #endif /* 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(mod); + if (module_dict == NULL) { + goto error; + } void **PyCurses_API = PyMem_Calloc(PyCurses_API_pointers, sizeof(void *)); if (PyCurses_API == NULL) { PyErr_NoMemory(); - return NULL; + goto error; } /* Initialize the C API pointer array */ PyCurses_API[0] = (void *)Py_NewRef(&PyCursesWindow_Type); @@ -4788,28 +4806,38 @@ 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; + goto error; } + int rc = PyDict_SetItemString(module_dict, "_C_API", c_api_object); Py_DECREF(c_api_object); + CHECK_RET_CODE(rc); /* For exception curses.error */ PyCursesError = PyErr_NewException("_curses.error", NULL, NULL); - PyDict_SetItemString(d, "error", PyCursesError); + if (PyCursesError == NULL) { + goto error; + } + rc = PyDict_SetItemString(module_dict, "error", PyCursesError); + Py_DECREF(PyCursesError); + CHECK_RET_CODE(rc); /* 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) { + goto error; + } + rc = PyDict_SetItemString(module_dict, "version", curses_version); + Py_DECREF(curses_version); + CHECK_RET_CODE(rc); + Py_INCREF(curses_version); + rc = PyDict_SetItemString(module_dict, "__version__", curses_version); + Py_CLEAR(curses_version); + CHECK_RET_CODE(rc); #ifdef NCURSES_VERSION /* ncurses_version */ @@ -4817,17 +4845,20 @@ PyInit__curses(void) version_type = _PyStructSequence_NewType(&ncurses_version_desc, Py_TPFLAGS_DISALLOW_INSTANTIATION); if (version_type == NULL) { - return NULL; + goto error; } - 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) { + goto error; } - PyDict_SetItemString(d, "ncurses_version", v); - Py_DECREF(v); + rc = PyDict_SetItemString(module_dict, "ncurses_version", ncurses_version); + Py_CLEAR(ncurses_version); + CHECK_RET_CODE(rc); #endif /* NCURSES_VERSION */ +#define SetDictInt(NAME, VALUE) DICT_ADD_INT_VALUE(module_dict, (NAME), (VALUE)) + SetDictInt("ERR", ERR); SetDictInt("OK", OK); @@ -4923,43 +4954,52 @@ 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(); + goto error; + } + 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) { + goto error; + } + int rc = PyDict_SetItemString(module_dict, fn_key_name, p_keycode); + Py_DECREF(p_keycode); + PyMem_Free(fn_key_name); + CHECK_RET_CODE(rc); + } + 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 - if (PyModule_AddType(m, &PyCursesWindow_Type) < 0) { - return NULL; - } - return m; + CHECK_RET_CODE(PyModule_AddType(mod, &PyCursesWindow_Type)); + return mod; + +error: + Py_XDECREF(mod); + return NULL; } + +#undef DICT_ADD_INT_VALUE +#undef CHECK_RET_CODE +#undef CHECK_STATE_FLAG diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index cb9750a69a632b..94d1444f7fec2c 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -412,10 +412,10 @@ Modules/_tkinter.c - trbInCmd - Include/datetime.h - PyDateTimeAPI - Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - Modules/_ctypes/malloc_closure.c - _pagesize - -Modules/_cursesmodule.c - initialised - -Modules/_cursesmodule.c - initialised_setupterm - -Modules/_cursesmodule.c - initialisedcolors - -Modules/_cursesmodule.c - screen_encoding - +Modules/_cursesmodule.c - CURSES_SETUPTERM_CALLED - +Modules/_cursesmodule.c - CURSES_INITSCR_CALLED - +Modules/_cursesmodule.c - CURSES_INITIALISED_COLORS - +Modules/_cursesmodule.c - CURSES_SCREEN_ENCODING - Modules/_elementtree.c - expat_capi - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation -