From 76ba47e6caffb55521ed508d428211537647d12e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Feb 2025 16:11:21 +0100 Subject: [PATCH 1/3] gh-128911: Use PyImport_ImportModuleAttr() function * Replace PyImport_ImportModule() + PyObject_GetAttr() with PyImport_ImportModuleAttr(). * Replace PyImport_ImportModule() + PyObject_GetAttrString() with PyImport_ImportModuleAttrString(). --- Modules/_ctypes/callbacks.c | 20 ++++---------------- Modules/_ctypes/stgdict.c | 2 +- Modules/_testcapi/code.c | 9 ++------- Modules/_testcapimodule.c | 11 +++-------- Modules/main.c | 31 ++++++++----------------------- PC/_testconsole.c | 15 +++++---------- Python/crossinterp.c | 9 +++------ Python/pythonrun.c | 29 ++++++----------------------- 8 files changed, 32 insertions(+), 94 deletions(-) diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index b84bd25af8ec2c..6dd6f6ec56d008 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -551,31 +551,19 @@ STDAPI DllGetClassObject(REFCLSID rclsid, long Call_CanUnloadNow(void) { - PyObject *mod, *func, *result; - long retval; - - mod = PyImport_ImportModule("ctypes"); - if (!mod) { -/* OutputDebugString("Could not import ctypes"); */ - /* We assume that this error can only occur when shutting - down, so we silently ignore it */ - PyErr_Clear(); - return E_FAIL; - } - /* Other errors cannot be raised, but are printed to stderr */ - func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); - Py_DECREF(mod); + PyObject *func = PyImport_ImportModuleAttrString("ctypes", + "DllCanUnloadNow"); if (!func) { goto error; } - result = _PyObject_CallNoArgs(func); + PyObject *result = _PyObject_CallNoArgs(func); Py_DECREF(func); if (!result) { goto error; } - retval = PyLong_AsLong(result); + long retval = PyLong_AsLong(result); if (PyErr_Occurred()) { Py_DECREF(result); goto error; diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index d63a46a3bc23d2..05239d85c44d2c 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -258,7 +258,7 @@ PyCStructUnionType_update_stginfo(PyObject *type, PyObject *fields, int isStruct } PyObject *layout_func = PyImport_ImportModuleAttrString("ctypes._layout", - "get_layout"); + "get_layout"); if (!layout_func) { goto error; } diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c index c0193489b6f340..94f752c9726189 100644 --- a/Modules/_testcapi/code.c +++ b/Modules/_testcapi/code.c @@ -47,7 +47,6 @@ static PyObject * test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) { PyObject *result = NULL; - PyObject *test_module = NULL; PyObject *test_func = NULL; // Get or initialize interpreter-specific code object storage index @@ -62,11 +61,8 @@ test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) // Get a function to test with // This can be any Python function. Use `test.test_misc.testfunction`. - test_module = PyImport_ImportModule("test.test_capi.test_misc"); - if (!test_module) { - goto finally; - } - test_func = PyObject_GetAttrString(test_module, "testfunction"); + test_func = PyImport_ImportModuleAttrString("test.test_capi.test_misc", + "testfunction"); if (!test_func) { goto finally; } @@ -102,7 +98,6 @@ test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) } result = Py_NewRef(Py_None); finally: - Py_XDECREF(test_module); Py_XDECREF(test_func); return result; } diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 09e74fd3cf20af..c84646ccf03fa7 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1057,15 +1057,10 @@ test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored)) if (ret != -1 || match == 0) goto error; - PyObject *mod_io = PyImport_ImportModule("_io"); - if (mod_io == NULL) { - return NULL; - } - /* bytesiobuf_getbuffer() */ - PyTypeObject *type = (PyTypeObject *)PyObject_GetAttrString( - mod_io, "_BytesIOBuffer"); - Py_DECREF(mod_io); + PyTypeObject *type = (PyTypeObject *)PyImport_ImportModuleAttrString( + "_io", + "_BytesIOBuffer"); if (type == NULL) { return NULL; } diff --git a/Modules/main.c b/Modules/main.c index 5bb1de2d04d30c..2d95a853d879d2 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -314,25 +314,19 @@ pymain_start_pyrepl_no_main(void) static int pymain_run_module(const wchar_t *modname, int set_argv0) { - PyObject *module, *runpy, *runmodule, *runargs, *result; + PyObject *module, *runmodule, *runargs, *result; if (PySys_Audit("cpython.run_module", "u", modname) < 0) { return pymain_exit_err_print(); } - runpy = PyImport_ImportModule("runpy"); - if (runpy == NULL) { - fprintf(stderr, "Could not import runpy module\n"); - return pymain_exit_err_print(); - } - runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main"); + runmodule = PyImport_ImportModuleAttrString("runpy", + "_run_module_as_main"); if (runmodule == NULL) { - fprintf(stderr, "Could not access runpy._run_module_as_main\n"); - Py_DECREF(runpy); + fprintf(stderr, "Could not import runpy._run_module_as_main\n"); return pymain_exit_err_print(); } module = PyUnicode_FromWideChar(modname, wcslen(modname)); if (module == NULL) { fprintf(stderr, "Could not convert module name to unicode\n"); - Py_DECREF(runpy); Py_DECREF(runmodule); return pymain_exit_err_print(); } @@ -340,7 +334,6 @@ pymain_run_module(const wchar_t *modname, int set_argv0) if (runargs == NULL) { fprintf(stderr, "Could not create arguments for runpy._run_module_as_main\n"); - Py_DECREF(runpy); Py_DECREF(runmodule); Py_DECREF(module); return pymain_exit_err_print(); @@ -350,7 +343,6 @@ pymain_run_module(const wchar_t *modname, int set_argv0) if (!result && PyErr_Occurred() == PyExc_KeyboardInterrupt) { _PyRuntime.signals.unhandled_keyboard_interrupt = 1; } - Py_DECREF(runpy); Py_DECREF(runmodule); Py_DECREF(module); Py_DECREF(runargs); @@ -497,24 +489,17 @@ pymain_run_startup(PyConfig *config, int *exitcode) static int pymain_run_interactive_hook(int *exitcode) { - PyObject *sys, *hook, *result; - sys = PyImport_ImportModule("sys"); - if (sys == NULL) { - goto error; - } - - hook = PyObject_GetAttrString(sys, "__interactivehook__"); - Py_DECREF(sys); + PyObject *hook = PyImport_ImportModuleAttrString("sys", + "__interactivehook__"); if (hook == NULL) { - PyErr_Clear(); - return 0; + goto error; } if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) { goto error; } - result = _PyObject_CallNoArgs(hook); + PyObject *result = _PyObject_CallNoArgs(hook); Py_DECREF(hook); if (result == NULL) { goto error; diff --git a/PC/_testconsole.c b/PC/_testconsole.c index 0dcea866f65d35..b3e97ce408e170 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -66,15 +66,10 @@ static PyObject * _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s) /*[clinic end generated code: output=58631a8985426ad3 input=68062f1bb2e52206]*/ { - INPUT_RECORD *rec = NULL; - - PyObject *mod = PyImport_ImportModule("_io"); - if (mod == NULL) { - return NULL; - } - - PyTypeObject *winconsoleio_type = (PyTypeObject *)PyObject_GetAttrString(mod, "_WindowsConsoleIO"); - Py_DECREF(mod); + PyTypeObject *winconsoleio_type; + winconsoleio_type = (PyTypeObject *)PyImport_ImportModuleAttrString( + "_io", + "_WindowsConsoleIO"); if (winconsoleio_type == NULL) { return NULL; } @@ -88,7 +83,7 @@ _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s) const wchar_t *p = (const wchar_t *)s->buf; DWORD size = (DWORD)s->len / sizeof(wchar_t); - rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); + INPUT_RECORD *rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); if (!rec) goto error; diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 7eb5bc267487d1..aa2c1cb78bce06 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -368,12 +368,9 @@ _convert_exc_to_TracebackException(PyObject *exc, PyObject **p_tbexc) PyObject *create = NULL; // This is inspired by _PyErr_Display(). - PyObject *tbmod = PyImport_ImportModule("traceback"); - if (tbmod == NULL) { - return -1; - } - PyObject *tbexc_type = PyObject_GetAttrString(tbmod, "TracebackException"); - Py_DECREF(tbmod); + PyObject *tbexc_type = PyImport_ImportModuleAttrString( + "traceback", + "TracebackException"); if (tbexc_type == NULL) { return -1; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 0da26ad3f9b4bd..ae0df9685ac159 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1108,22 +1108,15 @@ _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) int unhandled_keyboard_interrupt = _PyRuntime.signals.unhandled_keyboard_interrupt; // Try first with the stdlib traceback module - PyObject *traceback_module = PyImport_ImportModule("traceback"); - - if (traceback_module == NULL) { - goto fallback; - } - - PyObject *print_exception_fn = PyObject_GetAttrString(traceback_module, "_print_exception_bltin"); - + PyObject *print_exception_fn = PyImport_ImportModuleAttrString( + "traceback", + "_print_exception_bltin"); if (print_exception_fn == NULL || !PyCallable_Check(print_exception_fn)) { - Py_DECREF(traceback_module); goto fallback; } PyObject* result = PyObject_CallOneArg(print_exception_fn, value); - Py_DECREF(traceback_module); Py_XDECREF(print_exception_fn); if (result) { Py_DECREF(result); @@ -1371,27 +1364,18 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, } if (interactive_src) { - PyObject *linecache_module = PyImport_ImportModule("linecache"); - - if (linecache_module == NULL) { - Py_DECREF(co); - Py_DECREF(interactive_filename); - return NULL; - } - - PyObject *print_tb_func = PyObject_GetAttrString(linecache_module, "_register_code"); - + PyObject *print_tb_func = PyImport_ImportModuleAttrString( + "linecache", + "_register_code"); if (print_tb_func == NULL) { Py_DECREF(co); Py_DECREF(interactive_filename); - Py_DECREF(linecache_module); return NULL; } if (!PyCallable_Check(print_tb_func)) { Py_DECREF(co); Py_DECREF(interactive_filename); - Py_DECREF(linecache_module); Py_DECREF(print_tb_func); PyErr_SetString(PyExc_ValueError, "linecache._register_code is not callable"); return NULL; @@ -1406,7 +1390,6 @@ run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, Py_DECREF(interactive_filename); - Py_DECREF(linecache_module); Py_XDECREF(print_tb_func); Py_XDECREF(result); if (!result) { From a54e98b8fcc50853a9950ff9edbcc40edcedd6d4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Feb 2025 17:07:03 +0100 Subject: [PATCH 2/3] Fix pymain_run_interactive_hook() --- Modules/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/main.c b/Modules/main.c index 2d95a853d879d2..f8a2438cdd0d93 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -492,6 +492,11 @@ pymain_run_interactive_hook(int *exitcode) PyObject *hook = PyImport_ImportModuleAttrString("sys", "__interactivehook__"); if (hook == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + // no sys.__interactivehook__ attribute + PyErr_Clear(); + return 0; + } goto error; } From 3cf7a201cdada9226b6cf402b8b1d9215ce03ef3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Feb 2025 17:13:07 +0100 Subject: [PATCH 3/3] Revert _testconsole change: it uses the limited C API --- PC/_testconsole.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PC/_testconsole.c b/PC/_testconsole.c index b3e97ce408e170..0dcea866f65d35 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -66,10 +66,15 @@ static PyObject * _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s) /*[clinic end generated code: output=58631a8985426ad3 input=68062f1bb2e52206]*/ { - PyTypeObject *winconsoleio_type; - winconsoleio_type = (PyTypeObject *)PyImport_ImportModuleAttrString( - "_io", - "_WindowsConsoleIO"); + INPUT_RECORD *rec = NULL; + + PyObject *mod = PyImport_ImportModule("_io"); + if (mod == NULL) { + return NULL; + } + + PyTypeObject *winconsoleio_type = (PyTypeObject *)PyObject_GetAttrString(mod, "_WindowsConsoleIO"); + Py_DECREF(mod); if (winconsoleio_type == NULL) { return NULL; } @@ -83,7 +88,7 @@ _testconsole_write_input_impl(PyObject *module, PyObject *file, Py_buffer *s) const wchar_t *p = (const wchar_t *)s->buf; DWORD size = (DWORD)s->len / sizeof(wchar_t); - INPUT_RECORD *rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); + rec = (INPUT_RECORD*)PyMem_Calloc(size, sizeof(INPUT_RECORD)); if (!rec) goto error;