Skip to content

Commit a0de16a

Browse files
itamaroclaude
andcommitted
gh-157384: Refuse inittab names in PyImport_CreateModuleFromInitfunc()
Modules created by PyImport_CreateModuleFromInitfunc() share the extensions cache and sys.modules with built-in modules. Passing a spec whose name is registered in PyImport_Inittab either silently ignored the init function (for an already loaded single-phase builtin, or for "sys" and "builtins") or replaced the built-in module in sys.modules (for a multi-phase builtin). Raise ImportError instead. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HoZE3WdRWQshvinfBZ137N
1 parent 2cd6d4b commit a0de16a

5 files changed

Lines changed: 52 additions & 3 deletions

File tree

Doc/c-api/import.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,11 @@ Importing Modules
417417
(Custom importers should do this in their
418418
:py:meth:`~importlib.abc.Loader.exec_module` method.)
419419
420+
If the spec's name is registered in :c:var:`PyImport_Inittab` (which
421+
includes the :mod:`sys` and :mod:`builtins` modules), raise
422+
:exc:`ImportError`; a module cannot be both a built-in module and one
423+
created by this function.
424+
420425
On error, return NULL with an exception set.
421426
422427
.. versionadded:: 3.15

Lib/test/test_embed.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,15 @@ def test_create_module_from_initfunc(self):
278278
"my_test_extension.exec_slot_ran='yes'\n"
279279
"<module 'embedded_ext' (static-extension)>\n"
280280
"embedded_ext.executed='yes'\n"
281+
"ImportError: cannot create module 'sys' from an "
282+
"init function: a built-in module with this name "
283+
"is registered in PyImport_Inittab\n"
284+
"ImportError: cannot create module "
285+
"'create_static_module' from an init function: "
286+
"a built-in module with this name is registered "
287+
"in PyImport_Inittab\n"
288+
"sys.modules[\"create_static_module\"] "
289+
"is create_static_module=True\n"
281290
)
282291

283292
def test_inittab_submodule_multiphase(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:c:func:`PyImport_CreateModuleFromInitfunc` now raises :exc:`ImportError` if
2+
the spec's name is registered in :c:var:`PyImport_Inittab`, instead of
3+
silently ignoring *initfunc* or replacing the built-in module.

Programs/_testembed.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,13 @@ create_module(PyObject* self, PyObject* spec)
24252425
Py_DECREF(name);
24262426
return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext);
24272427
}
2428+
if (PyUnicode_EqualToUTF8(name, "sys")
2429+
|| PyUnicode_EqualToUTF8(name, "create_static_module")) {
2430+
// names registered in the inittab (core module / builtin):
2431+
// must be refused before the init function is called
2432+
Py_DECREF(name);
2433+
return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext);
2434+
}
24282435
PyErr_Format(PyExc_LookupError, "static module %R not found", name);
24292436
Py_DECREF(name);
24302437
return NULL;
@@ -2472,6 +2479,10 @@ test_create_module_from_initfunc(void)
24722479
L"import embedded_ext;"
24732480
L"print(embedded_ext);"
24742481
L"print(f'{embedded_ext.executed=}');"
2482+
// Names registered in the inittab are refused
2483+
L"try_create('sys');"
2484+
L"try_create('create_static_module');"
2485+
L"print(f'{sys.modules[\"create_static_module\"] is create_static_module=}');"
24752486
};
24762487
PyConfig config;
24772488
if (PyImport_AppendInittab("create_static_module",
@@ -2502,6 +2513,14 @@ test_create_module_from_initfunc(void)
25022513
" create_static_module.exec_module(module)\n"
25032514
" module.executed = 'yes'\n"
25042515
"sys.meta_path.append(StaticExtensionImporter)\n"
2516+
"def try_create(name):\n"
2517+
" spec = spec_from_loader(name, StaticExtensionImporter)\n"
2518+
" try:\n"
2519+
" create_static_module.create_module(spec)\n"
2520+
" except ImportError as exc:\n"
2521+
" print(f'ImportError: {exc}')\n"
2522+
" else:\n"
2523+
" print(f'no ImportError for {name}!')\n"
25052524
);
25062525
if (result < 0) {
25072526
fprintf(stderr, "PyRun_SimpleString() failed\n");

Python/import.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,10 +2486,10 @@ is_builtin(PyObject *name)
24862486
}
24872487

24882488
static struct _inittab*
2489-
lookup_inittab_entry(const struct _Py_ext_module_loader_info* info)
2489+
lookup_inittab_entry(PyObject *name)
24902490
{
24912491
for (struct _inittab *p = INITTAB; p->name != NULL; p++) {
2492-
if (_PyUnicode_EqualToASCIIString(info->name, p->name)) {
2492+
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
24932493
return p;
24942494
}
24952495
}
@@ -2534,7 +2534,7 @@ create_builtin(
25342534

25352535
PyModInitFunction p0 = NULL;
25362536
if (initfunc == NULL) {
2537-
struct _inittab *entry = lookup_inittab_entry(&info);
2537+
struct _inittab *entry = lookup_inittab_entry(info.name);
25382538
if (entry == NULL) {
25392539
mod = NULL;
25402540
_PyErr_SetModuleNotFoundError(name);
@@ -2601,6 +2601,19 @@ PyImport_CreateModuleFromInitfunc(
26012601
return NULL;
26022602
}
26032603

2604+
/* Built-in modules (including the core "sys" and "builtins" modules)
2605+
* share the extensions cache and sys.modules with modules created here.
2606+
* Refuse to create a module under a name registered in the inittab,
2607+
* rather than silently ignoring either initfunc or the other module. */
2608+
if (lookup_inittab_entry(name) != NULL) {
2609+
PyErr_Format(PyExc_ImportError,
2610+
"cannot create module %R from an init function: "
2611+
"a built-in module with this name is registered "
2612+
"in PyImport_Inittab", name);
2613+
Py_DECREF(name);
2614+
return NULL;
2615+
}
2616+
26042617
PyObject *mod = create_builtin(tstate, name, spec, initfunc);
26052618
Py_DECREF(name);
26062619
return mod;

0 commit comments

Comments
 (0)