From 0163940f416559bd1bf8b7f0056b01435b5fbc13 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 7 Feb 2024 18:23:02 -0700 Subject: [PATCH 01/13] Factor out _PyImport_RunDynamicModule(). --- Include/internal/pycore_importdl.h | 9 +++ Python/importdl.c | 96 ++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index 8bf7c2a48f66be..6d0c36e2daebee 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -40,6 +40,15 @@ extern int _Py_ext_module_loader_info_init_from_spec( struct _Py_ext_module_loader_info *info, PyObject *spec); +struct _Py_ext_module_loader_result { + PyModuleDef *def; + PyObject *module; +}; +extern int _PyImport_RunDynamicModule( + struct _Py_ext_module_loader_info *info, + FILE *fp, + struct _Py_ext_module_loader_result *res); + extern PyObject *_PyImport_LoadDynamicModuleWithSpec( struct _Py_ext_module_loader_info *info, PyObject *spec, diff --git a/Python/importdl.c b/Python/importdl.c index 65370249493325..0334ee7a9095f7 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -175,17 +175,23 @@ _Py_ext_module_loader_info_init_from_spec( } -PyObject * -_PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, - PyObject *spec, FILE *fp) +int +_PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, + FILE *fp, + struct _Py_ext_module_loader_result *res) { PyObject *m = NULL; const char *name_buf = PyBytes_AS_STRING(info->name_encoded); - const char *oldcontext; + const char *oldcontext, *newcontext; dl_funcptr exportfunc; PyModInitFunction p0; PyModuleDef *def; + newcontext = PyUnicode_AsUTF8(info->name); + if (newcontext == NULL) { + return -1; + } + #ifdef MS_WINDOWS exportfunc = _PyImport_FindSharedFuncptrWindows( info->hook_prefix, name_buf, info->filename, fp); @@ -209,7 +215,7 @@ _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, Py_DECREF(msg); } } - goto error; + return -1; } p0 = (PyModInitFunction)exportfunc; @@ -226,14 +232,14 @@ _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, "initialization of %s failed without raising an exception", name_buf); } - goto error; + return -1; } else if (PyErr_Occurred()) { _PyErr_FormatFromCause( PyExc_SystemError, "initialization of %s raised unreported exception", name_buf); m = NULL; - goto error; + return -1; } if (Py_IS_TYPE(m, NULL)) { /* This can happen when a PyModuleDef is returned without calling @@ -243,36 +249,74 @@ _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, "init function of %s returned uninitialized object", name_buf); m = NULL; /* prevent segfault in DECREF */ - goto error; - } - if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { - return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); + return -1; } - /* Fall back to single-phase init mechanism */ - - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - goto error; + if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { + /* multi-phase init */ + def = (PyModuleDef *)m; + m = NULL; + /* Run PyModule_FromDefAndSpec() to finish loading the module. */ } - - if (info->hook_prefix == nonascii_prefix) { - /* don't allow legacy init for non-ASCII module names */ + else if (info->hook_prefix == nonascii_prefix) { + /* It should have been multi-phase init? */ + /* Don't allow legacy init for non-ASCII module names. */ PyErr_Format( PyExc_SystemError, "initialization of %s did not return PyModuleDef", name_buf); - goto error; + Py_DECREF(m); + return -1; } + else { + /* single-phase init (legacy) */ + + def = PyModule_GetDef(m); + if (def == NULL) { + PyErr_Format(PyExc_SystemError, + "initialization of %s did not return an extension " + "module", name_buf); + Py_DECREF(m); + return -1; + } - /* Remember pointer to module init function. */ - def = PyModule_GetDef(m); - if (def == NULL) { - PyErr_Format(PyExc_SystemError, - "initialization of %s did not return an extension " - "module", name_buf); + /* Remember pointer to module init function. */ + def->m_base.m_init = p0; + + /* Run _PyImport_FixupExtensionObject() to finish loading the module. */ + } + + *res = (struct _Py_ext_module_loader_result){ + .def=def, + .module=m, + }; + return 0; +} + +PyObject * +_PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, + PyObject *spec, FILE *fp) +{ + PyObject *m = NULL; + const char *name_buf = PyBytes_AS_STRING(info->name_encoded); + PyModuleDef *def; + struct _Py_ext_module_loader_result res; + + if (_PyImport_RunDynamicModule(info, fp, &res) < 0) { + return NULL; + } + m = res.module; + def = res.def; + + if (m == NULL) { + return PyModule_FromDefAndSpec(def, spec); + } + + /* Fall back to single-phase init mechanism */ + + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { goto error; } - def->m_base.m_init = p0; /* Remember the filename as the __file__ attribute */ if (PyModule_AddObjectRef(m, "__file__", info->filename) < 0) { From e0ac947b73076b9d926bef00fa359719fc08ee4d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 7 Feb 2024 18:44:38 -0700 Subject: [PATCH 02/13] Drop _PyImport_LoadDynamicModuleWithSpec(). --- Include/internal/pycore_importdl.h | 5 ---- Python/import.c | 40 ++++++++++++++++++++++++--- Python/importdl.c | 44 ------------------------------ 3 files changed, 36 insertions(+), 53 deletions(-) diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index 6d0c36e2daebee..5e4c0fb00c69e2 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -49,11 +49,6 @@ extern int _PyImport_RunDynamicModule( FILE *fp, struct _Py_ext_module_loader_result *res); -extern PyObject *_PyImport_LoadDynamicModuleWithSpec( - struct _Py_ext_module_loader_info *info, - PyObject *spec, - FILE *fp); - /* Max length of module suffix searched for -- accommodates "module.slb" */ #define MAXSUFFIXSIZE 12 diff --git a/Python/import.c b/Python/import.c index 56011295f95190..de2ae28aca6cee 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3900,7 +3900,6 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { PyObject *mod = NULL; - FILE *fp; struct _Py_ext_module_loader_info info; if (_Py_ext_module_loader_info_init_from_spec(&info, spec) < 0) { @@ -3914,17 +3913,18 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } + /* Is multi-phase init or this is the first time being loaded. */ + if (PySys_Audit("import", "OOOOO", info.name, info.filename, Py_None, Py_None, Py_None) < 0) { goto finally; } - /* Is multi-phase init or this is the first time being loaded. */ - /* We would move this (and the fclose() below) into * _PyImport_GetModInitFunc(), but it isn't clear if the intervening * code relies on fp still being open. */ + FILE *fp; if (file != NULL) { fp = _Py_fopen_obj(info.filename, "r"); if (fp == NULL) { @@ -3935,7 +3935,39 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) fp = NULL; } - mod = _PyImport_LoadDynamicModuleWithSpec(&info, spec, fp); + struct _Py_ext_module_loader_result res; + if (_PyImport_RunDynamicModule(&info, fp, &res) < 0) { + goto finally; + } + mod = res.module; + + if (mod == NULL) { + /* multi-phase init */ + + mod = PyModule_FromDefAndSpec(res.def, spec); + } + else { + /* Fall back to single-phase init mechanism */ + + const char *name_buf = PyBytes_AS_STRING(info.name_encoded); + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { + Py_CLEAR(mod); + goto finally; + } + + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } + + PyObject *modules = get_modules_dict(tstate, true); + if (_PyImport_FixupExtensionObject( + mod, info.name, info.filename, modules) < 0) + { + Py_CLEAR(mod); + goto finally; + } + } // XXX Shouldn't this happen in the error cases too. if (fp) { diff --git a/Python/importdl.c b/Python/importdl.c index 0334ee7a9095f7..f9373f07a8b07a 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -293,48 +293,4 @@ _PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, return 0; } -PyObject * -_PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, - PyObject *spec, FILE *fp) -{ - PyObject *m = NULL; - const char *name_buf = PyBytes_AS_STRING(info->name_encoded); - PyModuleDef *def; - struct _Py_ext_module_loader_result res; - - if (_PyImport_RunDynamicModule(info, fp, &res) < 0) { - return NULL; - } - m = res.module; - def = res.def; - - if (m == NULL) { - return PyModule_FromDefAndSpec(def, spec); - } - - /* Fall back to single-phase init mechanism */ - - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - goto error; - } - - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(m, "__file__", info->filename) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } - - PyObject *modules = PyImport_GetModuleDict(); - if (_PyImport_FixupExtensionObject( - m, info->name, info->filename, modules) < 0) - { - goto error; - } - - return m; - -error: - Py_XDECREF(m); - return NULL; -} - #endif /* HAVE_DYNAMIC_LOADING */ From 1fee8ca48a88bfbf74da6528186329473517563a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 16 Apr 2024 14:52:27 -0600 Subject: [PATCH 03/13] Split up _PyImport_RunDynamicModule() along cross-interpreter-safe boundaries. --- Python/import.c | 5 --- Python/importdl.c | 98 +++++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/Python/import.c b/Python/import.c index de2ae28aca6cee..54d0a61075968a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3955,11 +3955,6 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } - PyObject *modules = get_modules_dict(tstate, true); if (_PyImport_FixupExtensionObject( mod, info.name, info.filename, modules) < 0) diff --git a/Python/importdl.c b/Python/importdl.c index f9373f07a8b07a..ca6e1ee95b1965 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -175,23 +175,12 @@ _Py_ext_module_loader_info_init_from_spec( } -int -_PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, - FILE *fp, - struct _Py_ext_module_loader_result *res) +static PyModInitFunction +_PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info, + FILE *fp) { - PyObject *m = NULL; const char *name_buf = PyBytes_AS_STRING(info->name_encoded); - const char *oldcontext, *newcontext; dl_funcptr exportfunc; - PyModInitFunction p0; - PyModuleDef *def; - - newcontext = PyUnicode_AsUTF8(info->name); - if (newcontext == NULL) { - return -1; - } - #ifdef MS_WINDOWS exportfunc = _PyImport_FindSharedFuncptrWindows( info->hook_prefix, name_buf, info->filename, fp); @@ -215,14 +204,25 @@ _PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, Py_DECREF(msg); } } - return -1; + return NULL; } - p0 = (PyModInitFunction)exportfunc; + return (PyModInitFunction)exportfunc; +} + +static int +_PyImport_RunModInitFunc(PyModInitFunction p0, + struct _Py_ext_module_loader_info *info, + struct _Py_ext_module_loader_result *p_res) +{ + struct _Py_ext_module_loader_result res = { + .singlephase=-1, + }; + const char *name_buf = PyBytes_AS_STRING(info->name_encoded); /* Package context is needed for single-phase init */ - oldcontext = _PyImport_SwapPackageContext(info->newcontext); - m = p0(); + const char *oldcontext = _PyImport_SwapPackageContext(info->newcontext); + PyObject *m = p0(); _PyImport_SwapPackageContext(oldcontext); if (m == NULL) { @@ -232,15 +232,19 @@ _PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, "initialization of %s failed without raising an exception", name_buf); } - return -1; + goto error; } else if (PyErr_Occurred()) { _PyErr_FormatFromCause( PyExc_SystemError, "initialization of %s raised unreported exception", name_buf); + /* We would probably be correct to decref m here, + * but we weren't doing so before, + * so we stick with doing nothing. */ m = NULL; - return -1; + goto error; } + if (Py_IS_TYPE(m, NULL)) { /* This can happen when a PyModuleDef is returned without calling * PyModuleDef_Init on it @@ -248,14 +252,16 @@ _PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, PyErr_Format(PyExc_SystemError, "init function of %s returned uninitialized object", name_buf); + /* Likewise, decref'ing here makes sense. However, the original + * code has a note about "prevent segfault in DECREF", + * so we play it safe and leave it alone. */ m = NULL; /* prevent segfault in DECREF */ - return -1; + goto error; } if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { /* multi-phase init */ - def = (PyModuleDef *)m; - m = NULL; + res.def = (PyModuleDef *)m; /* Run PyModule_FromDefAndSpec() to finish loading the module. */ } else if (info->hook_prefix == nonascii_prefix) { @@ -270,26 +276,54 @@ _PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, } else { /* single-phase init (legacy) */ + res.module = m; - def = PyModule_GetDef(m); - if (def == NULL) { + res.def = PyModule_GetDef(m); + if (res.def == NULL) { PyErr_Format(PyExc_SystemError, "initialization of %s did not return an extension " "module", name_buf); - Py_DECREF(m); - return -1; + goto error; } /* Remember pointer to module init function. */ - def->m_base.m_init = p0; + res.def->m_base.m_init = p0; + } + + *p_res = res; + return 0; + +error: + Py_CLEAR(res.module); + res.def = NULL; + *p_res = res; + return -1; +} + +int +_PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, + FILE *fp, + struct _Py_ext_module_loader_result *res) +{ + PyModInitFunction p0 = _PyImport_GetModInitFunc(info, fp); + if (p0 == NULL) { + return -1; + } + + if (_PyImport_RunModInitFunc(p0, info, res) < 0) { + return -1; + } + + if (res->module != NULL) { + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(res->module, "__file__", info->filename) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } /* Run _PyImport_FixupExtensionObject() to finish loading the module. */ } + /* else: Run PyModule_FromDefAndSpec() to finish loading the module. */ - *res = (struct _Py_ext_module_loader_result){ - .def=def, - .module=m, - }; return 0; } From a11eddbe312f4c273dd726b128a954fa5b424555 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 23 Apr 2024 14:38:37 -0600 Subject: [PATCH 04/13] Drop _PyImport_RunDynamicModule(). --- Include/internal/pycore_importdl.h | 9 +++++--- Python/import.c | 22 ++++++++++++++----- Python/importdl.c | 35 +++--------------------------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index 5e4c0fb00c69e2..55c26f2c5a475e 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -44,10 +44,13 @@ struct _Py_ext_module_loader_result { PyModuleDef *def; PyObject *module; }; -extern int _PyImport_RunDynamicModule( +extern PyModInitFunction _PyImport_GetModInitFunc( struct _Py_ext_module_loader_info *info, - FILE *fp, - struct _Py_ext_module_loader_result *res); + FILE *fp); +extern int _PyImport_RunModInitFunc( + PyModInitFunction p0, + struct _Py_ext_module_loader_info *info, + struct _Py_ext_module_loader_result *p_res); /* Max length of module suffix searched for -- accommodates "module.slb" */ diff --git a/Python/import.c b/Python/import.c index 54d0a61075968a..c9075b48edcfd9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3935,19 +3935,24 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) fp = NULL; } - struct _Py_ext_module_loader_result res; - if (_PyImport_RunDynamicModule(&info, fp, &res) < 0) { + PyModInitFunction p0 = _PyImport_GetModInitFunc(&info, fp); + if (p0 == NULL) { goto finally; } - mod = res.module; - if (mod == NULL) { - /* multi-phase init */ + struct _Py_ext_module_loader_result res; + if (_PyImport_RunModInitFunc(p0, &info, &res) < 0) { + assert(PyErr_Occurred()); + return NULL; + } + if (res.module == NULL) { + //assert(!is_singlephase(res.def)); mod = PyModule_FromDefAndSpec(res.def, spec); } else { - /* Fall back to single-phase init mechanism */ + assert(is_singlephase(res.def)); + mod = Py_NewRef(res.module); const char *name_buf = PyBytes_AS_STRING(info.name_encoded); if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { @@ -3955,6 +3960,11 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } + PyObject *modules = get_modules_dict(tstate, true); if (_PyImport_FixupExtensionObject( mod, info.name, info.filename, modules) < 0) diff --git a/Python/importdl.c b/Python/importdl.c index ca6e1ee95b1965..b6f495749e5d63 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -175,7 +175,7 @@ _Py_ext_module_loader_info_init_from_spec( } -static PyModInitFunction +PyModInitFunction _PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info, FILE *fp) { @@ -210,14 +210,12 @@ _PyImport_GetModInitFunc(struct _Py_ext_module_loader_info *info, return (PyModInitFunction)exportfunc; } -static int +int _PyImport_RunModInitFunc(PyModInitFunction p0, struct _Py_ext_module_loader_info *info, struct _Py_ext_module_loader_result *p_res) { - struct _Py_ext_module_loader_result res = { - .singlephase=-1, - }; + struct _Py_ext_module_loader_result res = {0}; const char *name_buf = PyBytes_AS_STRING(info->name_encoded); /* Package context is needed for single-phase init */ @@ -300,31 +298,4 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, return -1; } -int -_PyImport_RunDynamicModule(struct _Py_ext_module_loader_info *info, - FILE *fp, - struct _Py_ext_module_loader_result *res) -{ - PyModInitFunction p0 = _PyImport_GetModInitFunc(info, fp); - if (p0 == NULL) { - return -1; - } - - if (_PyImport_RunModInitFunc(p0, info, res) < 0) { - return -1; - } - - if (res->module != NULL) { - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(res->module, "__file__", info->filename) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } - - /* Run _PyImport_FixupExtensionObject() to finish loading the module. */ - } - /* else: Run PyModule_FromDefAndSpec() to finish loading the module. */ - - return 0; -} - #endif /* HAVE_DYNAMIC_LOADING */ From daf7295237c10bb544cc582618bb798af3c3d0b6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 16 Apr 2024 16:49:34 -0600 Subject: [PATCH 05/13] Factor out create_dynamic(). --- Python/import.c | 142 +++++++++++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 55 deletions(-) diff --git a/Python/import.c b/Python/import.c index c9075b48edcfd9..5942c805219b09 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1431,6 +1431,90 @@ clear_singlephase_extension(PyInterpreterState *interp, return 0; } +static PyObject * +create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, + PyObject *file, PyObject *spec) +{ + PyObject *mod = NULL; + + /* We would move this (and the fclose() below) into + * _PyImport_GetModInitFunc(), but it isn't clear if the intervening + * code relies on fp still being open. */ + FILE *fp; + if (file != NULL) { + fp = _Py_fopen_obj(info->filename, "r"); + if (fp == NULL) { + goto finally; + } + } + else { + fp = NULL; + } + + PyModInitFunction p0 = _PyImport_GetModInitFunc(info, fp); + if (p0 == NULL) { + goto finally; + } + + struct _Py_ext_module_loader_result res; + if (_PyImport_RunModInitFunc(p0, info, &res) < 0) { + assert(PyErr_Occurred()); + goto finally; + } + + if (res.module == NULL) { + //assert(!is_singlephase(res.def)); + mod = PyModule_FromDefAndSpec(res.def, spec); + } + else { + assert(is_singlephase(res.def)); + assert(!is_core_module(tstate->interp, info->name, info->filename)); + assert(!is_core_module(tstate->interp, info->name, info->name)); + mod = Py_NewRef(res.module); + + const char *name_buf = PyBytes_AS_STRING(info->name_encoded); + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { + Py_CLEAR(mod); + goto finally; + } + + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(mod, "__file__", info->filename) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } + + struct singlephase_global_update singlephase = {0}; + // gh-88216: Extensions and def->m_base.m_copy can be updated + // when the extension module doesn't support sub-interpreters. + if (res.def->m_size == -1) { + singlephase.m_dict = PyModule_GetDict(mod); + assert(singlephase.m_dict != NULL); + } + if (update_global_state_for_extension( + tstate, info->filename, info->name, res.def, &singlephase) < 0) + { + Py_CLEAR(mod); + goto finally; + } + + PyObject *modules = get_modules_dict(tstate, true); + if (finish_singlephase_extension( + tstate, mod, res.def, info->name, modules) < 0) + { + Py_CLEAR(mod); + goto finally; + } + } + + // XXX Shouldn't this happen in the error cases too. + if (fp) { + fclose(fp); + } + +finally: + return mod; +} + /*******************/ /* builtin modules */ @@ -3921,64 +4005,12 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } - /* We would move this (and the fclose() below) into - * _PyImport_GetModInitFunc(), but it isn't clear if the intervening - * code relies on fp still being open. */ - FILE *fp; - if (file != NULL) { - fp = _Py_fopen_obj(info.filename, "r"); - if (fp == NULL) { - goto finally; - } - } - else { - fp = NULL; - } - - PyModInitFunction p0 = _PyImport_GetModInitFunc(&info, fp); - if (p0 == NULL) { + /* Is multi-phase init or this is the first time being loaded. */ + mod = create_dynamic(tstate, &info, file, spec); + if (mod == NULL) { goto finally; } - struct _Py_ext_module_loader_result res; - if (_PyImport_RunModInitFunc(p0, &info, &res) < 0) { - assert(PyErr_Occurred()); - return NULL; - } - - if (res.module == NULL) { - //assert(!is_singlephase(res.def)); - mod = PyModule_FromDefAndSpec(res.def, spec); - } - else { - assert(is_singlephase(res.def)); - mod = Py_NewRef(res.module); - - const char *name_buf = PyBytes_AS_STRING(info.name_encoded); - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - Py_CLEAR(mod); - goto finally; - } - - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } - - PyObject *modules = get_modules_dict(tstate, true); - if (_PyImport_FixupExtensionObject( - mod, info.name, info.filename, modules) < 0) - { - Py_CLEAR(mod); - goto finally; - } - } - - // XXX Shouldn't this happen in the error cases too. - if (fp) { - fclose(fp); - } - finally: _Py_ext_module_loader_info_clear(&info); return mod; From 3a5eba6906e736227577d7d7dadf1707edd8aad5 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 16 Apr 2024 17:23:50 -0600 Subject: [PATCH 06/13] Drop _PyImport_FixupExtensionObject(). --- Include/internal/pycore_import.h | 5 +--- Include/moduleobject.h | 2 +- Python/import.c | 41 -------------------------------- 3 files changed, 2 insertions(+), 46 deletions(-) diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 8d7f0543f8d315..b02769903a6f9b 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -29,9 +29,6 @@ extern int _PyImport_FixupBuiltin( const char *name, /* UTF-8 encoded string */ PyObject *modules ); -// We could probably drop this: -extern int _PyImport_FixupExtensionObject(PyObject*, PyObject *, - PyObject *, PyObject *); // Export for many shared extensions, like '_json' PyAPI_FUNC(PyObject*) _PyImport_GetModuleAttr(PyObject *, PyObject *); @@ -55,7 +52,7 @@ struct _import_runtime_state { Only legacy (single-phase init) extension modules are added and only if they support multiple initialization (m_size >- 0) or are imported in the main interpreter. - This is initialized lazily in _PyImport_FixupExtensionObject(). + This is initialized lazily in fix_up_extension() in import.c. Modules are added there and looked up in _imp.find_extension(). */ _Py_hashtable_t *hashtable; } extensions; diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 42b87cc4e91012..83f8c2030dbb8f 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -53,7 +53,7 @@ typedef struct PyModuleDef_Base { /* A copy of the module's __dict__ after the first time it was loaded. This is only set/used for legacy modules that do not support multiple initializations. - It is set by _PyImport_FixupExtensionObject(). */ + It is set by fix_up_extension() in import.c. */ PyObject* m_copy; } PyModuleDef_Base; diff --git a/Python/import.c b/Python/import.c index 5942c805219b09..72776ff4b5c90e 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1285,47 +1285,6 @@ finish_singlephase_extension(PyThreadState *tstate, return 0; } -int -_PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, - PyObject *filename, PyObject *modules) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - if (mod == NULL || !PyModule_Check(mod)) { - PyErr_BadInternalCall(); - return -1; - } - PyModuleDef *def = PyModule_GetDef(mod); - if (def == NULL) { - PyErr_BadInternalCall(); - return -1; - } - - /* Only single-phase init extension modules can reach here. */ - assert(is_singlephase(def)); - assert(!is_core_module(tstate->interp, name, filename)); - assert(!is_core_module(tstate->interp, name, name)); - - struct singlephase_global_update singlephase = {0}; - // gh-88216: Extensions and def->m_base.m_copy can be updated - // when the extension module doesn't support sub-interpreters. - if (def->m_size == -1) { - singlephase.m_dict = PyModule_GetDict(mod); - assert(singlephase.m_dict != NULL); - } - if (update_global_state_for_extension( - tstate, filename, name, def, &singlephase) < 0) - { - return -1; - } - - if (finish_singlephase_extension(tstate, mod, def, name, modules) < 0) { - return -1; - } - - return 0; -} - static PyObject * import_find_extension(PyThreadState *tstate, From 2ab4bd820100eacb5e2fe481a022a50f947c8b69 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 18 Apr 2024 15:09:46 -0600 Subject: [PATCH 07/13] Add some asserts to _PyImport_RunModInitFunc(). --- Python/importdl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Python/importdl.c b/Python/importdl.c index b6f495749e5d63..3ae9c6a4a37596 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -278,6 +278,7 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, res.def = PyModule_GetDef(m); if (res.def == NULL) { + PyErr_Clear(); PyErr_Format(PyExc_SystemError, "initialization of %s did not return an extension " "module", name_buf); @@ -288,10 +289,12 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, res.def->m_base.m_init = p0; } + assert(!PyErr_Occurred()); *p_res = res; return 0; error: + assert(PyErr_Occurred()); Py_CLEAR(res.module); res.def = NULL; *p_res = res; From 9b398444a4850d1a56c2dbae6234611d52c79fac Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 18 Apr 2024 16:24:25 -0600 Subject: [PATCH 08/13] Check the module returned by import_find_extension() to ensure single-phase init. --- Python/import.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Python/import.c b/Python/import.c index 72776ff4b5c90e..cc02f65ed23804 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1557,7 +1557,12 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) } PyObject *mod = import_find_extension(tstate, &info); - if (mod || _PyErr_Occurred(tstate)) { + if (mod != NULL) { + assert(!_PyErr_Occurred(tstate)); + assert(is_singlephase(_PyModule_GetDef(mod))); + goto finally; + } + else if (_PyErr_Occurred(tstate)) { goto finally; } @@ -3943,20 +3948,23 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { PyObject *mod = NULL; + PyThreadState *tstate = _PyThreadState_GET(); struct _Py_ext_module_loader_info info; if (_Py_ext_module_loader_info_init_from_spec(&info, spec) < 0) { return NULL; } - PyThreadState *tstate = _PyThreadState_GET(); mod = import_find_extension(tstate, &info); - if (mod != NULL || _PyErr_Occurred(tstate)) { - assert(mod == NULL || !_PyErr_Occurred(tstate)); + if (mod != NULL) { + assert(!_PyErr_Occurred(tstate)); + assert(is_singlephase(_PyModule_GetDef(mod))); goto finally; } - - /* Is multi-phase init or this is the first time being loaded. */ + else if (_PyErr_Occurred(tstate)) { + goto finally; + } + /* Otherwise it must be multi-phase init or the first time it's loaded. */ if (PySys_Audit("import", "OOOOO", info.name, info.filename, Py_None, Py_None, Py_None) < 0) From c253654e7f70d6800a615b04fa50b4e349b159a5 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 18 Apr 2024 19:16:44 -0600 Subject: [PATCH 09/13] We already know the def is okay. --- Python/import.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Python/import.c b/Python/import.c index cc02f65ed23804..4b2b81cc7f54f4 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1270,7 +1270,7 @@ finish_singlephase_extension(PyThreadState *tstate, PyObject *name, PyObject *modules) { assert(mod != NULL && PyModule_Check(mod)); - assert(def == PyModule_GetDef(mod)); + assert(def == _PyModule_GetDef(mod)); if (_modules_by_index_set(tstate->interp, def, mod) < 0) { return -1; @@ -1395,6 +1395,7 @@ create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, PyObject *file, PyObject *spec) { PyObject *mod = NULL; + PyModuleDef *def = NULL; /* We would move this (and the fclose() below) into * _PyImport_GetModInitFunc(), but it isn't clear if the intervening @@ -1421,15 +1422,23 @@ create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, goto finally; } - if (res.module == NULL) { - //assert(!is_singlephase(res.def)); - mod = PyModule_FromDefAndSpec(res.def, spec); + mod = res.module; + res.module = NULL; + def = res.def; + assert(def != NULL); + + if (mod == NULL) { + //assert(!is_singlephase(def)); + mod = PyModule_FromDefAndSpec(def, spec); + if (mod == NULL) { + goto finally; + } } else { - assert(is_singlephase(res.def)); + assert(is_singlephase(def)); assert(!is_core_module(tstate->interp, info->name, info->filename)); assert(!is_core_module(tstate->interp, info->name, info->name)); - mod = Py_NewRef(res.module); + mod = Py_NewRef(mod); const char *name_buf = PyBytes_AS_STRING(info->name_encoded); if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { @@ -1445,12 +1454,12 @@ create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, struct singlephase_global_update singlephase = {0}; // gh-88216: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. - if (res.def->m_size == -1) { + if (def->m_size == -1) { singlephase.m_dict = PyModule_GetDict(mod); assert(singlephase.m_dict != NULL); } if (update_global_state_for_extension( - tstate, info->filename, info->name, res.def, &singlephase) < 0) + tstate, info->filename, info->name, def, &singlephase) < 0) { Py_CLEAR(mod); goto finally; @@ -1458,7 +1467,7 @@ create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, PyObject *modules = get_modules_dict(tstate, true); if (finish_singlephase_extension( - tstate, mod, res.def, info->name, modules) < 0) + tstate, mod, def, info->name, modules) < 0) { Py_CLEAR(mod); goto finally; From 8172748bb9a900c52624505de21689aa4f80b8fc Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 23 Apr 2024 17:19:11 -0600 Subject: [PATCH 10/13] Drop create_dynamic(). --- Python/import.c | 176 ++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 96 deletions(-) diff --git a/Python/import.c b/Python/import.c index 4b2b81cc7f54f4..3a713e9e7eea87 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1390,99 +1390,6 @@ clear_singlephase_extension(PyInterpreterState *interp, return 0; } -static PyObject * -create_dynamic(PyThreadState *tstate, struct _Py_ext_module_loader_info *info, - PyObject *file, PyObject *spec) -{ - PyObject *mod = NULL; - PyModuleDef *def = NULL; - - /* We would move this (and the fclose() below) into - * _PyImport_GetModInitFunc(), but it isn't clear if the intervening - * code relies on fp still being open. */ - FILE *fp; - if (file != NULL) { - fp = _Py_fopen_obj(info->filename, "r"); - if (fp == NULL) { - goto finally; - } - } - else { - fp = NULL; - } - - PyModInitFunction p0 = _PyImport_GetModInitFunc(info, fp); - if (p0 == NULL) { - goto finally; - } - - struct _Py_ext_module_loader_result res; - if (_PyImport_RunModInitFunc(p0, info, &res) < 0) { - assert(PyErr_Occurred()); - goto finally; - } - - mod = res.module; - res.module = NULL; - def = res.def; - assert(def != NULL); - - if (mod == NULL) { - //assert(!is_singlephase(def)); - mod = PyModule_FromDefAndSpec(def, spec); - if (mod == NULL) { - goto finally; - } - } - else { - assert(is_singlephase(def)); - assert(!is_core_module(tstate->interp, info->name, info->filename)); - assert(!is_core_module(tstate->interp, info->name, info->name)); - mod = Py_NewRef(mod); - - const char *name_buf = PyBytes_AS_STRING(info->name_encoded); - if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { - Py_CLEAR(mod); - goto finally; - } - - /* Remember the filename as the __file__ attribute */ - if (PyModule_AddObjectRef(mod, "__file__", info->filename) < 0) { - PyErr_Clear(); /* Not important enough to report */ - } - - struct singlephase_global_update singlephase = {0}; - // gh-88216: Extensions and def->m_base.m_copy can be updated - // when the extension module doesn't support sub-interpreters. - if (def->m_size == -1) { - singlephase.m_dict = PyModule_GetDict(mod); - assert(singlephase.m_dict != NULL); - } - if (update_global_state_for_extension( - tstate, info->filename, info->name, def, &singlephase) < 0) - { - Py_CLEAR(mod); - goto finally; - } - - PyObject *modules = get_modules_dict(tstate, true); - if (finish_singlephase_extension( - tstate, mod, def, info->name, modules) < 0) - { - Py_CLEAR(mod); - goto finally; - } - } - - // XXX Shouldn't this happen in the error cases too. - if (fp) { - fclose(fp); - } - -finally: - return mod; -} - /*******************/ /* builtin modules */ @@ -3957,6 +3864,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { PyObject *mod = NULL; + PyModuleDef *def = NULL; PyThreadState *tstate = _PyThreadState_GET(); struct _Py_ext_module_loader_info info; @@ -3981,12 +3889,88 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } - /* Is multi-phase init or this is the first time being loaded. */ - mod = create_dynamic(tstate, &info, file, spec); - if (mod == NULL) { + /* We would move this (and the fclose() below) into + * _PyImport_GetModInitFunc(), but it isn't clear if the intervening + * code relies on fp still being open. */ + FILE *fp; + if (file != NULL) { + fp = _Py_fopen_obj(info.filename, "r"); + if (fp == NULL) { + goto finally; + } + } + else { + fp = NULL; + } + + PyModInitFunction p0 = _PyImport_GetModInitFunc(&info, fp); + if (p0 == NULL) { goto finally; } + struct _Py_ext_module_loader_result res; + if (_PyImport_RunModInitFunc(p0, &info, &res) < 0) { + assert(PyErr_Occurred()); + goto finally; + } + + mod = res.module; + res.module = NULL; + def = res.def; + assert(def != NULL); + + if (mod == NULL) { + //assert(!is_singlephase(def)); + mod = PyModule_FromDefAndSpec(def, spec); + if (mod == NULL) { + goto finally; + } + } + else { + assert(is_singlephase(def)); + assert(!is_core_module(tstate->interp, info.name, info.filename)); + assert(!is_core_module(tstate->interp, info.name, info.name)); + mod = Py_NewRef(mod); + + const char *name_buf = PyBytes_AS_STRING(info.name_encoded); + if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { + Py_CLEAR(mod); + goto finally; + } + + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { + PyErr_Clear(); /* Not important enough to report */ + } + + struct singlephase_global_update singlephase = {0}; + // gh-88216: Extensions and def->m_base.m_copy can be updated + // when the extension module doesn't support sub-interpreters. + if (def->m_size == -1) { + singlephase.m_dict = PyModule_GetDict(mod); + assert(singlephase.m_dict != NULL); + } + if (update_global_state_for_extension( + tstate, info.filename, info.name, def, &singlephase) < 0) + { + Py_CLEAR(mod); + goto finally; + } + + PyObject *modules = get_modules_dict(tstate, true); + if (finish_singlephase_extension( + tstate, mod, def, info.name, modules) < 0) + { + Py_CLEAR(mod); + goto finally; + } + } + + // XXX Shouldn't this happen in the error cases too. + if (fp) { + fclose(fp); + } + finally: _Py_ext_module_loader_info_clear(&info); return mod; From 4e72371690b2e59b344b8e8af74dadc7d0ce6e62 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Apr 2024 10:49:29 -0600 Subject: [PATCH 11/13] Update the comment about extensions. --- Python/import.c | 86 ++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/Python/import.c b/Python/import.c index 3a713e9e7eea87..fb45be58907a54 100644 --- a/Python/import.c +++ b/Python/import.c @@ -632,44 +632,45 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) (6). first time (not found in _PyRuntime.imports.extensions): A. _imp_create_dynamic_impl() -> import_find_extension() - B. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec() - C. _PyImport_LoadDynamicModuleWithSpec(): load - D. _PyImport_LoadDynamicModuleWithSpec(): call - E. -> PyModule_Create() -> PyModule_Create2() + B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc() + C. _PyImport_GetModInitFunc(): load + D. _imp_create_dynamic_impl() -> _PyImport_RunModInitFunc() + E. _PyImport_RunModInitFunc(): call + F. -> PyModule_Create() -> PyModule_Create2() -> PyModule_CreateInitialized() - F. PyModule_CreateInitialized() -> PyModule_New() - G. PyModule_CreateInitialized(): allocate mod->md_state - H. PyModule_CreateInitialized() -> PyModule_AddFunctions() - I. PyModule_CreateInitialized() -> PyModule_SetDocString() - J. PyModule_CreateInitialized(): set mod->md_def - K. : initialize the module, etc. - L. _PyImport_LoadDynamicModuleWithSpec() - -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() - M. _PyImport_LoadDynamicModuleWithSpec(): set def->m_base.m_init - N. _PyImport_LoadDynamicModuleWithSpec() -> _PyImport_FixupExtensionObject() - O. _PyImport_FixupExtensionObject() -> update_global_state_for_extension() - P. update_global_state_for_extension(): - copy __dict__ into def->m_base.m_copy - Q. update_global_state_for_extension(): - add it to _PyRuntime.imports.extensions - R. _PyImport_FixupExtensionObject() -> finish_singlephase_extension() - S. finish_singlephase_extension(): - add it to interp->imports.modules_by_index - T. finish_singlephase_extension(): add it to sys.modules - U. _imp_create_dynamic_impl(): set __file__ - - Step (P) is skipped for core modules (sys/builtins). + G. PyModule_CreateInitialized() -> PyModule_New() + H. PyModule_CreateInitialized(): allocate mod->md_state + I. PyModule_CreateInitialized() -> PyModule_AddFunctions() + J. PyModule_CreateInitialized() -> PyModule_SetDocString() + K. PyModule_CreateInitialized(): set mod->md_def + L. : initialize the module, etc. + M. _PyImport_RunModInitFunc(): set def->m_base.m_init + N. _imp_create_dynamic_impl() + -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() + O. _imp_create_dynamic_impl(): set __file__ + P. _imp_create_dynamic_impl() -> update_global_state_for_extension() + Q. update_global_state_for_extension(): + copy __dict__ into def->m_base.m_copy + R. update_global_state_for_extension(): + add it to _PyRuntime.imports.extensions + S. _imp_create_dynamic_impl() -> finish_singlephase_extension() + T. finish_singlephase_extension(): + add it to interp->imports.modules_by_index + U. finish_singlephase_extension(): add it to sys.modules + + Step (Q) is skipped for core modules (sys/builtins). (6). subsequent times (found in _PyRuntime.imports.extensions): A. _imp_create_dynamic_impl() -> import_find_extension() - B. import_find_extension() -> import_add_module() - C. if name in sys.modules: use that module - D. else: + B. import_find_extension() + -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() + C. import_find_extension() -> import_add_module() + D. if name in sys.modules: use that module + E. else: 1. import_add_module() -> PyModule_NewObject() 2. import_add_module(): set it on sys.modules - E. import_find_extension(): copy the "m_copy" dict into __dict__ - F. _imp_create_dynamic_impl() - -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() + F. import_find_extension(): copy the "m_copy" dict into __dict__ + G. import_find_extension(): add to modules_by_index (10). (every time): A. noop @@ -678,19 +679,22 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) ...for single-phase init modules, where m_size >= 0: (6). not main interpreter and never loaded there - every time (not found in _PyRuntime.imports.extensions): - A-N. (same as for m_size == -1) - O-Q. (skipped) - R-U. (same as for m_size == -1) + A-O. (same as for m_size == -1) + P-R. (skipped) + S-U. (same as for m_size == -1) (6). main interpreter - first time (not found in _PyRuntime.imports.extensions): - A-O. (same as for m_size == -1) - P. (skipped) - Q-U. (same as for m_size == -1) + A-Q. (same as for m_size == -1) + R. (skipped) + S-U. (same as for m_size == -1) - (6). previously loaded in main interpreter (found in _PyRuntime.imports.extensions): + (6). subsequent times (found in _PyRuntime.imports.extensions): A. _imp_create_dynamic_impl() -> import_find_extension() - B. import_find_extension(): call def->m_base.m_init - C. import_find_extension(): add the module to sys.modules + B. import_find_extension() + -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() + C. import_find_extension(): call def->m_base.m_init (see above) + D. import_find_extension(): add the module to sys.modules + E. import_find_extension(): add to modules_by_index (10). every time: A. noop From 52f0656cb0fd6e136616605a031ac67e35eb348c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Apr 2024 13:55:50 -0600 Subject: [PATCH 12/13] Move setting m_init to _imp_create_dynamic_impl(). --- Python/import.c | 3 +++ Python/importdl.c | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Python/import.c b/Python/import.c index fb45be58907a54..6ff75d40d708de 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3942,6 +3942,9 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) goto finally; } + /* Remember pointer to module init function. */ + res.def->m_base.m_init = p0; + /* Remember the filename as the __file__ attribute */ if (PyModule_AddObjectRef(mod, "__file__", info.filename) < 0) { PyErr_Clear(); /* Not important enough to report */ diff --git a/Python/importdl.c b/Python/importdl.c index 3ae9c6a4a37596..0a086846d092d2 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -218,11 +218,15 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, struct _Py_ext_module_loader_result res = {0}; const char *name_buf = PyBytes_AS_STRING(info->name_encoded); + /* Call the module init function. */ + /* Package context is needed for single-phase init */ const char *oldcontext = _PyImport_SwapPackageContext(info->newcontext); PyObject *m = p0(); _PyImport_SwapPackageContext(oldcontext); + /* Validate the result (and populate "res". */ + if (m == NULL) { if (!PyErr_Occurred()) { PyErr_Format( @@ -284,9 +288,6 @@ _PyImport_RunModInitFunc(PyModInitFunction p0, "module", name_buf); goto error; } - - /* Remember pointer to module init function. */ - res.def->m_base.m_init = p0; } assert(!PyErr_Occurred()); From a1d12589184268c2a7a3dc0b85eded678757520a Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Apr 2024 14:50:57 -0600 Subject: [PATCH 13/13] Fix a refleak. --- Python/import.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/import.c b/Python/import.c index 6ff75d40d708de..f440cd52866b60 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3934,7 +3934,6 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) assert(is_singlephase(def)); assert(!is_core_module(tstate->interp, info.name, info.filename)); assert(!is_core_module(tstate->interp, info.name, info.name)); - mod = Py_NewRef(mod); const char *name_buf = PyBytes_AS_STRING(info.name_encoded); if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy