From 4864c3edd0b7451401d00dbd876f6dc7d0c868c9 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 12 Jan 2023 11:58:46 -0700 Subject: [PATCH 1/4] Factor out module_exec(). --- Modules/_testinternalcapi.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b14b8ac3c74054..37176a8ed7d82c 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -638,6 +638,19 @@ static PyMethodDef TestMethods[] = { }; +/* initialization function */ + +static int +module_exec(PyObject *module) +{ + if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD", + PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { + return 1; + } + + return 0; +} + static struct PyModuleDef _testcapimodule = { PyModuleDef_HEAD_INIT, "_testinternalcapi", @@ -658,15 +671,9 @@ PyInit__testinternalcapi(void) if (module == NULL) { return NULL; } - - if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD", - PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { - goto error; + if (module_exec(module) < 0) { + Py_DECREF(module); + return NULL; } - return module; - -error: - Py_DECREF(module); - return NULL; } From 5dd5521bec95f8cfd208975f3d693dcfd42a54bd Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 12 Jan 2023 12:09:29 -0700 Subject: [PATCH 2/4] Switch to multi-phase init. --- Modules/_testinternalcapi.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 37176a8ed7d82c..7c5ea34e803c1b 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -613,7 +613,7 @@ get_interp_settings(PyObject *self, PyObject *args) } -static PyMethodDef TestMethods[] = { +static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, {"test_bswap", test_bswap, METH_NOARGS}, @@ -651,29 +651,27 @@ module_exec(PyObject *module) return 0; } +static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_exec, module_exec}, + {0, NULL}, +}; + static struct PyModuleDef _testcapimodule = { - PyModuleDef_HEAD_INIT, - "_testinternalcapi", - NULL, - -1, - TestMethods, - NULL, - NULL, - NULL, - NULL + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_testinternalcapi", + .m_doc = NULL, + .m_size = 0, + .m_methods = module_functions, + .m_slots = module_slots, + /* There is no module state (or globals) to traverse/clear/free. */ + .m_traverse = NULL, + .m_clear = NULL, + .m_free = NULL, }; PyMODINIT_FUNC PyInit__testinternalcapi(void) { - PyObject *module = PyModule_Create(&_testcapimodule); - if (module == NULL) { - return NULL; - } - if (module_exec(module) < 0) { - Py_DECREF(module); - return NULL; - } - return module; + return PyModuleDef_Init(&_testcapimodule); } From b2ad82c53254445f81290c897536d390984bdd64 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 12 Jan 2023 12:33:27 -0700 Subject: [PATCH 3/4] Add module state. --- Modules/_testinternalcapi.c | 104 +++++++++++++++++--- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - Tools/c-analyzer/cpython/ignored.tsv | 2 +- 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 7c5ea34e803c1b..f53929f80f8adf 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -28,6 +28,60 @@ #include "clinic/_testinternalcapi.c.h" + +#define MODULE_NAME "_testinternalcapi" + + +static PyObject * +_get_current_module(void) +{ + // We ensured it was imported in _run_script(). + PyObject *name = PyUnicode_FromString(MODULE_NAME); + if (name == NULL) { + return NULL; + } + PyObject *mod = PyImport_GetModule(name); + Py_DECREF(name); + if (mod == NULL) { + return NULL; + } + assert(mod != Py_None); + return mod; +} + + +/* module state *************************************************************/ + +typedef struct { + PyObject *record_list; +} module_state; + +static inline module_state * +get_module_state(PyObject *mod) +{ + assert(mod != NULL); + module_state *state = PyModule_GetState(mod); + assert(state != NULL); + return state; +} + +static int +traverse_module_state(module_state *state, visitproc visit, void *arg) +{ + Py_VISIT(state->record_list); + return 0; +} + +static int +clear_module_state(module_state *state) +{ + Py_CLEAR(state->record_list); + return 0; +} + + +/* module functions *********************************************************/ + /*[clinic input] module _testinternalcapi [clinic start generated code]*/ @@ -496,13 +550,12 @@ decode_locale_ex(PyObject *self, PyObject *args) return res; } -static PyObject *record_list = NULL; - static PyObject * set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args)) { + module_state *state = get_module_state(self); _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), _PyEval_EvalFrameDefault); - Py_CLEAR(record_list); + Py_CLEAR(state->record_list); Py_RETURN_NONE; } @@ -510,7 +563,10 @@ static PyObject * record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc) { if (PyFunction_Check(f->f_funcobj)) { - PyList_Append(record_list, ((PyFunctionObject *)f->f_funcobj)->func_name); + PyObject *module = _get_current_module(); + assert(module != NULL); + module_state *state = get_module_state(module); + PyList_Append(state->record_list, ((PyFunctionObject *)f->f_funcobj)->func_name); } return _PyEval_EvalFrameDefault(tstate, f, exc); } @@ -519,11 +575,12 @@ record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc) static PyObject * set_eval_frame_record(PyObject *self, PyObject *list) { + module_state *state = get_module_state(self); if (!PyList_Check(list)) { PyErr_SetString(PyExc_TypeError, "argument must be a list"); return NULL; } - Py_XSETREF(record_list, Py_NewRef(list)); + Py_XSETREF(state->record_list, Py_NewRef(list)); _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), record_eval); Py_RETURN_NONE; } @@ -656,17 +713,42 @@ static struct PyModuleDef_Slot module_slots[] = { {0, NULL}, }; +static int +module_traverse(PyObject *module, visitproc visit, void *arg) +{ + module_state *state = get_module_state(module); + assert(state != NULL); + traverse_module_state(state, visit, arg); + return 0; +} + +static int +module_clear(PyObject *module) +{ + module_state *state = get_module_state(module); + assert(state != NULL); + (void)clear_module_state(state); + return 0; +} + +static void +module_free(void *module) +{ + module_state *state = get_module_state(module); + assert(state != NULL); + (void)clear_module_state(state); +} + static struct PyModuleDef _testcapimodule = { .m_base = PyModuleDef_HEAD_INIT, - .m_name = "_testinternalcapi", + .m_name = MODULE_NAME, .m_doc = NULL, - .m_size = 0, + .m_size = sizeof(module_state), .m_methods = module_functions, .m_slots = module_slots, - /* There is no module state (or globals) to traverse/clear/free. */ - .m_traverse = NULL, - .m_clear = NULL, - .m_free = NULL, + .m_traverse = module_traverse, + .m_clear = module_clear, + .m_free = (freefunc)module_free, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 479221cbd4b682..cd08782edce484 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -523,7 +523,6 @@ Modules/_asynciomodule.c - all_tasks - Modules/_asynciomodule.c - current_tasks - Modules/_asynciomodule.c - iscoroutine_typecache - Modules/_ctypes/_ctypes.c - _ctypes_ptrtype_cache - -Modules/_testinternalcapi.c - record_list - Modules/_tkinter.c - tcl_lock - Modules/_tkinter.c - excInCmd - Modules/_tkinter.c - valInCmd - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 02531692a88447..ee46fb847fc577 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -483,7 +483,7 @@ Modules/_testcapimodule.c - g_type_watchers_installed - Modules/_testimportmultiple.c - _barmodule - Modules/_testimportmultiple.c - _foomodule - Modules/_testimportmultiple.c - _testimportmultiple - -Modules/_testinternalcapi.c - TestMethods - +Modules/_testinternalcapi.c - module_functions - Modules/_testinternalcapi.c - _testcapimodule - Modules/_testmultiphase.c - Example_Type_slots - Modules/_testmultiphase.c - Example_Type_spec - From 686523fad555077aef511b7caa075f106d25f5fd Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 12 Jan 2023 12:35:21 -0700 Subject: [PATCH 4/4] Drop some globals from the "ignored" list. --- Tools/c-analyzer/cpython/ignored.tsv | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index ee46fb847fc577..849e20a1b0f4eb 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -483,8 +483,6 @@ Modules/_testcapimodule.c - g_type_watchers_installed - Modules/_testimportmultiple.c - _barmodule - Modules/_testimportmultiple.c - _foomodule - Modules/_testimportmultiple.c - _testimportmultiple - -Modules/_testinternalcapi.c - module_functions - -Modules/_testinternalcapi.c - _testcapimodule - Modules/_testmultiphase.c - Example_Type_slots - Modules/_testmultiphase.c - Example_Type_spec - Modules/_testmultiphase.c - Example_methods -