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) {