summaryrefslogtreecommitdiffstats
path: root/Python/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c312
1 files changed, 159 insertions, 153 deletions
diff --git a/Python/import.c b/Python/import.c
index f440cd5..447114a 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -634,29 +634,30 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
A. _imp_create_dynamic_impl() -> import_find_extension()
B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc()
C. _PyImport_GetModInitFunc(): load <module init func>
- D. _imp_create_dynamic_impl() -> _PyImport_RunModInitFunc()
- E. _PyImport_RunModInitFunc(): call <module init func>
- F. <module init func> -> PyModule_Create() -> PyModule_Create2()
- -> PyModule_CreateInitialized()
- 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. <module init func>: 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
+ D. _imp_create_dynamic_impl() -> import_run_extension()
+ E. import_run_extension() -> _PyImport_RunModInitFunc()
+ F. _PyImport_RunModInitFunc(): call <module init func>
+ G. <module init func> -> PyModule_Create() -> PyModule_Create2()
+ -> PyModule_CreateInitialized()
+ H. PyModule_CreateInitialized() -> PyModule_New()
+ I. PyModule_CreateInitialized(): allocate mod->md_state
+ J. PyModule_CreateInitialized() -> PyModule_AddFunctions()
+ K. PyModule_CreateInitialized() -> PyModule_SetDocString()
+ L. PyModule_CreateInitialized(): set mod->md_def
+ M. <module init func>: initialize the module, etc.
+ N. _PyImport_RunModInitFunc(): set def->m_base.m_init
+ O. import_run_extension()
+ -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed()
+ P. import_run_extension(): set __file__
+ Q. import_run_extension() -> update_global_state_for_extension()
+ R. update_global_state_for_extension():
+ copy __dict__ into def->m_base.m_copy
+ S. update_global_state_for_extension():
+ add it to _PyRuntime.imports.extensions
+ T. import_run_extension() -> finish_singlephase_extension()
+ U. finish_singlephase_extension():
+ add it to interp->imports.modules_by_index
+ V. finish_singlephase_extension(): add it to sys.modules
Step (Q) is skipped for core modules (sys/builtins).
@@ -679,14 +680,14 @@ _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-O. (same as for m_size == -1)
- P-R. (skipped)
- S-U. (same as for m_size == -1)
+ A-P. (same as for m_size == -1)
+ Q-S. (skipped)
+ T-V. (same as for m_size == -1)
(6). main interpreter - first time (not found in _PyRuntime.imports.extensions):
- A-Q. (same as for m_size == -1)
- R. (skipped)
- S-U. (same as for m_size == -1)
+ A-R. (same as for m_size == -1)
+ S. (skipped)
+ T-V. (same as for m_size == -1)
(6). subsequent times (found in _PyRuntime.imports.extensions):
A. _imp_create_dynamic_impl() -> import_find_extension()
@@ -703,19 +704,21 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
...for multi-phase init modules:
(6). every time:
- A. _imp_create_dynamic_impl() -> import_find_extension() (not found)
- B. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec()
- C. _PyImport_LoadDynamicModuleWithSpec(): load module init func
- D. _PyImport_LoadDynamicModuleWithSpec(): call module init func
- E. _PyImport_LoadDynamicModuleWithSpec() -> PyModule_FromDefAndSpec()
- F. PyModule_FromDefAndSpec(): gather/check moduledef slots
- G. if there's a Py_mod_create slot:
+ A. _imp_create_dynamic_impl() -> import_find_extension() (not found)
+ B. _imp_create_dynamic_impl() -> _PyImport_GetModInitFunc()
+ C. _PyImport_GetModInitFunc(): load <module init func>
+ D. _imp_create_dynamic_impl() -> import_run_extension()
+ E. import_run_extension() -> _PyImport_RunModInitFunc()
+ F. _PyImport_RunModInitFunc(): call <module init func>
+ G. import_run_extension() -> PyModule_FromDefAndSpec()
+ H. PyModule_FromDefAndSpec(): gather/check moduledef slots
+ I. if there's a Py_mod_create slot:
1. PyModule_FromDefAndSpec(): call its function
- H. else:
+ J. else:
1. PyModule_FromDefAndSpec() -> PyModule_NewObject()
- I: PyModule_FromDefAndSpec(): set mod->md_def
- J. PyModule_FromDefAndSpec() -> _add_methods_to_object()
- K. PyModule_FromDefAndSpec() -> PyModule_SetDocString()
+ K: PyModule_FromDefAndSpec(): set mod->md_def
+ L. PyModule_FromDefAndSpec() -> _add_methods_to_object()
+ M. PyModule_FromDefAndSpec() -> PyModule_SetDocString()
(10). every time:
A. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic()
@@ -1236,6 +1239,20 @@ update_global_state_for_extension(PyThreadState *tstate,
assert(!is_core_module(tstate->interp, name, path));
assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0);
assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0);
+ /* XXX gh-88216: The copied dict is owned by the current
+ * interpreter. That's a problem if the interpreter has
+ * its own obmalloc state or if the module is successfully
+ * imported into such an interpreter. If the interpreter
+ * has its own GIL then there may be data races and
+ * PyImport_ClearModulesByIndex() can crash. Normally,
+ * a single-phase init module cannot be imported in an
+ * isolated interpreter, but there are ways around that.
+ * Hence, heere be dragons! Ideally we would instead do
+ * something like make a read-only, immortal copy of the
+ * dict using PyMem_RawMalloc() and store *that* in m_copy.
+ * Then we'd need to make sure to clear that when the
+ * runtime is finalized, rather than in
+ * PyImport_ClearModulesByIndex(). */
if (def->m_base.m_copy) {
/* Somebody already imported the module,
likely under a different name.
@@ -1299,6 +1316,7 @@ import_find_extension(PyThreadState *tstate,
if (def == NULL) {
return NULL;
}
+ assert(is_singlephase(def));
/* It may have been successfully imported previously
in an interpreter that allows legacy modules
@@ -1337,14 +1355,25 @@ import_find_extension(PyThreadState *tstate,
Py_DECREF(mod);
return NULL;
}
+ /* We can't set mod->md_def if it's missing,
+ * because _PyImport_ClearModulesByIndex() might break
+ * due to violating interpreter isolation. See the note
+ * in fix_up_extension_for_interpreter(). Until that
+ * is solved, we leave md_def set to NULL. */
+ assert(_PyModule_GetDef(mod) == NULL
+ || _PyModule_GetDef(mod) == def);
}
else {
- if (def->m_base.m_init == NULL)
+ if (def->m_base.m_init == NULL) {
return NULL;
- mod = def->m_base.m_init();
- if (mod == NULL) {
+ }
+ struct _Py_ext_module_loader_result res;
+ if (_PyImport_RunModInitFunc(def->m_base.m_init, info, &res) < 0) {
return NULL;
}
+ assert(!PyErr_Occurred());
+ mod = res.module;
+ // XXX __file__ doesn't get set!
if (PyObject_SetItem(modules, info->name, mod) == -1) {
Py_DECREF(mod);
return NULL;
@@ -1364,6 +1393,86 @@ import_find_extension(PyThreadState *tstate,
return mod;
}
+static PyObject *
+import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
+ struct _Py_ext_module_loader_info *info,
+ PyObject *spec, PyObject *modules)
+{
+ PyObject *mod = NULL;
+ PyModuleDef *def = NULL;
+
+ struct _Py_ext_module_loader_result res;
+ if (_PyImport_RunModInitFunc(p0, info, &res) < 0) {
+ /* We discard res.def. */
+ assert(res.module == NULL);
+ assert(PyErr_Occurred());
+ goto finally;
+ }
+ assert(!PyErr_Occurred());
+
+ mod = res.module;
+ res.module = NULL;
+ def = res.def;
+ assert(def != NULL);
+
+ if (mod == NULL) {
+ //assert(!is_singlephase(def));
+ assert(mod == NULL);
+ mod = PyModule_FromDefAndSpec(def, spec);
+ if (mod == NULL) {
+ goto finally;
+ }
+ }
+ else {
+ assert(is_singlephase(def));
+ assert(PyModule_Check(mod));
+
+ const char *name_buf = PyBytes_AS_STRING(info->name_encoded);
+ if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
+ Py_CLEAR(mod);
+ goto finally;
+ }
+
+ /* Remember pointer to module init function. */
+ def->m_base.m_init = p0;
+
+ if (info->filename != NULL) {
+ /* 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
+ && !is_core_module(tstate->interp, info->name, info->path))
+ {
+ singlephase.m_dict = PyModule_GetDict(mod);
+ assert(singlephase.m_dict != NULL);
+ }
+ if (update_global_state_for_extension(
+ tstate, info->path, 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;
+ }
+ }
+
+finally:
+ return mod;
+}
+
+
static int
clear_singlephase_extension(PyInterpreterState *interp,
PyObject *name, PyObject *path)
@@ -1469,10 +1578,8 @@ is_builtin(PyObject *name)
static PyObject*
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
{
- PyModuleDef *def = NULL;
-
struct _Py_ext_module_loader_info info;
- if (_Py_ext_module_loader_info_init(&info, name, NULL) < 0) {
+ if (_Py_ext_module_loader_info_init_for_builtin(&info, name) < 0) {
return NULL;
}
@@ -1506,54 +1613,9 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
goto finally;
}
- mod = p0();
- if (mod == NULL) {
- goto finally;
- }
-
- if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
- def = (PyModuleDef*)mod;
- assert(!is_singlephase(def));
- mod = PyModule_FromDefAndSpec(def, spec);
- if (mod == NULL) {
- goto finally;
- }
- }
- else {
- assert(PyModule_Check(mod));
- def = PyModule_GetDef(mod);
- if (def == NULL) {
- Py_CLEAR(mod);
- goto finally;
- }
- assert(is_singlephase(def));
-
- /* Remember pointer to module init function. */
- def->m_base.m_init = p0;
-
- 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
- && !is_core_module(tstate->interp, info.name, info.path))
- {
- singlephase.m_dict = PyModule_GetDict(mod);
- assert(singlephase.m_dict != NULL);
- }
- if (update_global_state_for_extension(
- tstate, info.name, info.path, 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;
- }
- }
+ /* Now load it. */
+ mod = import_run_extension(
+ tstate, p0, &info, spec, get_modules_dict(tstate, true));
finally:
_Py_ext_module_loader_info_clear(&info);
@@ -3868,7 +3930,6 @@ _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;
@@ -3912,67 +3973,12 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
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);
-
+ mod = import_run_extension(
+ tstate, p0, &info, spec, get_modules_dict(tstate, true));
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));
-
- const char *name_buf = PyBytes_AS_STRING(info.name_encoded);
- if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
- Py_CLEAR(mod);
- 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 */
- }
-
- 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.
+ // XXX Shouldn't this happen in the error cases too (i.e. in "finally")?
if (fp) {
fclose(fp);
}