Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Doc/c-api/import.rst
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,11 @@ Importing Modules
(Custom importers should do this in their
:py:meth:`~importlib.abc.Loader.exec_module` method.)

If the spec's name is registered in :c:var:`PyImport_Inittab` (which
includes the :mod:`sys` and :mod:`builtins` modules), raise
:exc:`ImportError`; a module cannot be both a built-in module and one
created by this function.

On error, return NULL with an exception set.

.. versionadded:: 3.15
9 changes: 9 additions & 0 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,15 @@ def test_create_module_from_initfunc(self):
"my_test_extension.exec_slot_ran='yes'\n"
"<module 'embedded_ext' (static-extension)>\n"
"embedded_ext.executed='yes'\n"
"ImportError: cannot create module 'sys' from an "
"init function: a built-in module with this name "
"is registered in PyImport_Inittab\n"
"ImportError: cannot create module "
"'create_static_module' from an init function: "
"a built-in module with this name is registered "
"in PyImport_Inittab\n"
"sys.modules[\"create_static_module\"] "
"is create_static_module=True\n"
)

def test_inittab_submodule_multiphase(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:c:func:`PyImport_CreateModuleFromInitfunc` now raises :exc:`ImportError` if
the spec's name is registered in :c:var:`PyImport_Inittab`, instead of
silently ignoring *initfunc* or replacing the built-in module.
19 changes: 19 additions & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -2425,6 +2425,13 @@ create_module(PyObject* self, PyObject* spec)
Py_DECREF(name);
return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext);
}
if (PyUnicode_EqualToUTF8(name, "sys")
|| PyUnicode_EqualToUTF8(name, "create_static_module")) {
// names registered in the inittab (core module / builtin):
// must be refused before the init function is called
Py_DECREF(name);
return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext);
}
PyErr_Format(PyExc_LookupError, "static module %R not found", name);
Py_DECREF(name);
return NULL;
Expand Down Expand Up @@ -2472,6 +2479,10 @@ test_create_module_from_initfunc(void)
L"import embedded_ext;"
L"print(embedded_ext);"
L"print(f'{embedded_ext.executed=}');"
// Names registered in the inittab are refused
L"try_create('sys');"
L"try_create('create_static_module');"
L"print(f'{sys.modules[\"create_static_module\"] is create_static_module=}');"
};
PyConfig config;
if (PyImport_AppendInittab("create_static_module",
Expand Down Expand Up @@ -2502,6 +2513,14 @@ test_create_module_from_initfunc(void)
" create_static_module.exec_module(module)\n"
" module.executed = 'yes'\n"
"sys.meta_path.append(StaticExtensionImporter)\n"
"def try_create(name):\n"
" spec = spec_from_loader(name, StaticExtensionImporter)\n"
" try:\n"
" create_static_module.create_module(spec)\n"
" except ImportError as exc:\n"
" print(f'ImportError: {exc}')\n"
" else:\n"
" print(f'no ImportError for {name}!')\n"
);
if (result < 0) {
fprintf(stderr, "PyRun_SimpleString() failed\n");
Expand Down
19 changes: 16 additions & 3 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -2486,10 +2486,10 @@ is_builtin(PyObject *name)
}

static struct _inittab*
lookup_inittab_entry(const struct _Py_ext_module_loader_info* info)
lookup_inittab_entry(PyObject *name)
{
for (struct _inittab *p = INITTAB; p->name != NULL; p++) {
if (_PyUnicode_EqualToASCIIString(info->name, p->name)) {
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
return p;
}
}
Expand Down Expand Up @@ -2534,7 +2534,7 @@ create_builtin(

PyModInitFunction p0 = NULL;
if (initfunc == NULL) {
struct _inittab *entry = lookup_inittab_entry(&info);
struct _inittab *entry = lookup_inittab_entry(info.name);
if (entry == NULL) {
mod = NULL;
_PyErr_SetModuleNotFoundError(name);
Expand Down Expand Up @@ -2601,6 +2601,19 @@ PyImport_CreateModuleFromInitfunc(
return NULL;
}

/* Built-in modules (including the core "sys" and "builtins" modules)
* share the extensions cache and sys.modules with modules created here.
* Refuse to create a module under a name registered in the inittab,
* rather than silently ignoring either initfunc or the other module. */
if (lookup_inittab_entry(name) != NULL) {
PyErr_Format(PyExc_ImportError,
"cannot create module %R from an init function: "
"a built-in module with this name is registered "
"in PyImport_Inittab", name);
Py_DECREF(name);
return NULL;
}

PyObject *mod = create_builtin(tstate, name, spec, initfunc);
Py_DECREF(name);
return mod;
Expand Down
Loading