Skip to content

bpo-28411: Isolate PyInterpreterState.modules #3575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
17 changes: 14 additions & 3 deletions Include/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject(
);
#endif
PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyImport_IsInitialized(PyInterpreterState *);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
PyObject *name
);
#endif
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyImport_AddModuleObject(PyObject *, PyObject *);
#endif
PyAPI_FUNC(PyObject *) PyImport_AddModule(
const char *name /* UTF-8 encoded string */
);
Expand Down Expand Up @@ -92,14 +98,19 @@ PyAPI_FUNC(int) _PyImport_ReleaseLock(void);
PyAPI_FUNC(void) _PyImport_ReInitLock(void);

PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
const char *name /* UTF-8 encoded string */
const char *name, /* UTF-8 encoded string */
PyObject *modules
);
PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObject(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) _PyImport_FindExtensionObjectEx(PyObject *, PyObject *,
PyObject *);
PyAPI_FUNC(int) _PyImport_FixupBuiltin(
PyObject *mod,
const char *name /* UTF-8 encoded string */
const char *name, /* UTF-8 encoded string */
PyObject *modules
);
PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *, PyObject *);
PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *,
PyObject *, PyObject *);

struct _inittab {
const char *name; /* ASCII encoded string */
Expand Down
4 changes: 4 additions & 0 deletions Include/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def);

PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*,
int apiver);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PyModule_CreateInitialized(struct PyModuleDef*,
int apiver);
#endif

#ifdef Py_LIMITED_API
#define PyModule_Create(module) \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Change direct usage of PyInterpreterState.modules to PyImport_GetModuleDict().
Also introduce more uniformity in other code that deals with sys.modules.
This helps reduce complications when working on sys.modules.
12 changes: 9 additions & 3 deletions Objects/moduleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,18 @@ _add_methods_to_object(PyObject *module, PyObject *name, PyMethodDef *functions)

PyObject *
PyModule_Create2(struct PyModuleDef* module, int module_api_version)
{
if (!_PyImport_IsInitialized(PyThreadState_GET()->interp))
Py_FatalError("Python import machinery not initialized");
return _PyModule_CreateInitialized(module, module_api_version);
}

PyObject *
_PyModule_CreateInitialized(struct PyModuleDef* module, int module_api_version)
{
const char* name;
PyModuleObject *m;
PyInterpreterState *interp = PyThreadState_Get()->interp;
if (interp->modules == NULL)
Py_FatalError("Python import machinery not initialized");

if (!PyModuleDef_Init(module))
return NULL;
name = module->m_name;
Expand Down
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3902,7 +3902,6 @@ import_copyreg(void)
{
PyObject *copyreg_str;
PyObject *copyreg_module;
PyInterpreterState *interp = PyThreadState_GET()->interp;
_Py_IDENTIFIER(copyreg);

copyreg_str = _PyUnicode_FromId(&PyId_copyreg);
Expand All @@ -3914,7 +3913,8 @@ import_copyreg(void)
by storing a reference to the cached module in a static variable, but
this broke when multiple embedded interpreters were in use (see issue
#17408 and #19088). */
copyreg_module = PyDict_GetItemWithError(interp->modules, copyreg_str);
PyObject *modules = PyImport_GetModuleDict();
copyreg_module = PyDict_GetItemWithError(modules, copyreg_str);
if (copyreg_module != NULL) {
Py_INCREF(copyreg_module);
return copyreg_module;
Expand Down
2 changes: 1 addition & 1 deletion Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2685,7 +2685,7 @@ _PyBuiltin_Init(void)
PyType_Ready(&PyZip_Type) < 0)
return NULL;

mod = PyModule_Create(&builtinsmodule);
mod = _PyModule_CreateInitialized(&builtinsmodule, PYTHON_API_VERSION);
if (mod == NULL)
return NULL;
dict = PyModule_GetDict(mod);
Expand Down
59 changes: 45 additions & 14 deletions Python/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ PyImport_GetModuleDict(void)
return interp->modules;
}

/* In some corner cases it is important to be sure that the import
machinery has been initialized (or not cleaned up yet). For
example, see issue #4236 and PyModule_Create2(). */

int
_PyImport_IsInitialized(PyInterpreterState *interp)
{
if (interp->modules == NULL)
return 0;
return 1;
}

/* List of names to clear in sys */
static const char * const sys_deletes[] = {
Expand Down Expand Up @@ -323,7 +334,7 @@ PyImport_Cleanup(void)
Py_ssize_t pos;
PyObject *key, *value, *dict;
PyInterpreterState *interp = PyThreadState_GET()->interp;
PyObject *modules = interp->modules;
PyObject *modules = PyImport_GetModuleDict();
PyObject *weaklist = NULL;
const char * const *p;

Expand Down Expand Up @@ -511,9 +522,9 @@ PyImport_GetMagicTag(void)

int
_PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
PyObject *filename)
PyObject *filename, PyObject *modules)
{
PyObject *modules, *dict, *key;
PyObject *dict, *key;
struct PyModuleDef *def;
int res;
if (extensions == NULL) {
Expand All @@ -530,7 +541,6 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
PyErr_BadInternalCall();
return -1;
}
modules = PyImport_GetModuleDict();
if (PyDict_SetItem(modules, name, mod) < 0)
return -1;
if (_PyState_AddModule(mod, def) < 0) {
Expand Down Expand Up @@ -562,20 +572,28 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
}

int
_PyImport_FixupBuiltin(PyObject *mod, const char *name)
_PyImport_FixupBuiltin(PyObject *mod, const char *name, PyObject *modules)
{
int res;
PyObject *nameobj;
nameobj = PyUnicode_InternFromString(name);
if (nameobj == NULL)
return -1;
res = _PyImport_FixupExtensionObject(mod, nameobj, nameobj);
res = _PyImport_FixupExtensionObject(mod, nameobj, nameobj, modules);
Py_DECREF(nameobj);
return res;
}

PyObject *
_PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
{
PyObject *modules = PyImport_GetModuleDict();
return _PyImport_FindExtensionObjectEx(name, filename, modules);
}

PyObject *
_PyImport_FindExtensionObjectEx(PyObject *name, PyObject *filename,
PyObject *modules)
{
PyObject *mod, *mdict, *key;
PyModuleDef* def;
Expand All @@ -592,7 +610,7 @@ _PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
/* Module does not support repeated initialization */
if (def->m_base.m_copy == NULL)
return NULL;
mod = PyImport_AddModuleObject(name);
mod = _PyImport_AddModuleObject(name, modules);
if (mod == NULL)
return NULL;
mdict = PyModule_GetDict(mod);
Expand All @@ -607,14 +625,14 @@ _PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
mod = def->m_base.m_init();
if (mod == NULL)
return NULL;
if (PyDict_SetItem(PyImport_GetModuleDict(), name, mod) == -1) {
if (PyDict_SetItem(modules, name, mod) == -1) {
Py_DECREF(mod);
return NULL;
}
Py_DECREF(mod);
}
if (_PyState_AddModule(mod, def) < 0) {
PyDict_DelItem(PyImport_GetModuleDict(), name);
PyDict_DelItem(modules, name);
Py_DECREF(mod);
return NULL;
}
Expand All @@ -626,13 +644,13 @@ _PyImport_FindExtensionObject(PyObject *name, PyObject *filename)
}

PyObject *
_PyImport_FindBuiltin(const char *name)
_PyImport_FindBuiltin(const char *name, PyObject *modules)
{
PyObject *res, *nameobj;
nameobj = PyUnicode_InternFromString(name);
if (nameobj == NULL)
return NULL;
res = _PyImport_FindExtensionObject(nameobj, nameobj);
res = _PyImport_FindExtensionObjectEx(nameobj, nameobj, modules);
Py_DECREF(nameobj);
return res;
}
Expand All @@ -647,6 +665,12 @@ PyObject *
PyImport_AddModuleObject(PyObject *name)
{
PyObject *modules = PyImport_GetModuleDict();
return _PyImport_AddModuleObject(name, modules);
}

PyObject *
_PyImport_AddModuleObject(PyObject *name, PyObject *modules)
{
PyObject *m;

if ((m = PyDict_GetItemWithError(modules, name)) != NULL &&
Expand Down Expand Up @@ -1042,6 +1066,7 @@ _imp_create_builtin(PyObject *module, PyObject *spec)
return NULL;
}

PyObject *modules = NULL;
for (p = PyImport_Inittab; p->name != NULL; p++) {
PyModuleDef *def;
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
Expand All @@ -1067,7 +1092,11 @@ _imp_create_builtin(PyObject *module, PyObject *spec)
return NULL;
}
def->m_base.m_init = p->initfunc;
if (_PyImport_FixupExtensionObject(mod, name, name) < 0) {
if (modules == NULL) {
modules = PyImport_GetModuleDict();
}
if (_PyImport_FixupExtensionObject(mod, name, name,
modules) < 0) {
Py_DECREF(name);
return NULL;
}
Expand Down Expand Up @@ -1511,7 +1540,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
Py_INCREF(abs_name);
}

mod = PyDict_GetItem(interp->modules, abs_name);
PyObject *modules = PyImport_GetModuleDict();
mod = PyDict_GetItem(modules, abs_name);
if (mod != NULL && mod != Py_None) {
_Py_IDENTIFIER(__spec__);
_Py_IDENTIFIER(_initializing);
Expand Down Expand Up @@ -1598,7 +1628,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
goto error;
}

final_mod = PyDict_GetItem(interp->modules, to_return);
PyObject *modules = PyImport_GetModuleDict();
final_mod = PyDict_GetItem(modules, to_return);
Py_DECREF(to_return);
if (final_mod == NULL) {
PyErr_Format(PyExc_KeyError,
Expand Down
3 changes: 2 additions & 1 deletion Python/importdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp)
else
Py_INCREF(path);

if (_PyImport_FixupExtensionObject(m, name_unicode, path) < 0)
PyObject *modules = PyImport_GetModuleDict();
if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0)
goto error;

Py_DECREF(name_unicode);
Expand Down
60 changes: 32 additions & 28 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,20 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
if (!_PyFloat_Init())
Py_FatalError("Py_InitializeCore: can't init float");

interp->modules = PyDict_New();
if (interp->modules == NULL)
PyObject *modules = PyDict_New();
if (modules == NULL)
Py_FatalError("Py_InitializeCore: can't make modules dictionary");
interp->modules = modules;

sysmod = _PySys_BeginInit();
if (sysmod == NULL)
Py_FatalError("Py_InitializeCore: can't initialize sys");
interp->sysdict = PyModule_GetDict(sysmod);
if (interp->sysdict == NULL)
Py_FatalError("Py_InitializeCore: can't initialize sys dict");
Py_INCREF(interp->sysdict);
PyDict_SetItemString(interp->sysdict, "modules", modules);
_PyImport_FixupBuiltin(sysmod, "sys", modules);

/* Init Unicode implementation; relies on the codec registry */
if (_PyUnicode_Init() < 0)
Expand All @@ -689,7 +700,7 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
bimod = _PyBuiltin_Init();
if (bimod == NULL)
Py_FatalError("Py_InitializeCore: can't initialize builtins modules");
_PyImport_FixupBuiltin(bimod, "builtins");
_PyImport_FixupBuiltin(bimod, "builtins", modules);
interp->builtins = PyModule_GetDict(bimod);
if (interp->builtins == NULL)
Py_FatalError("Py_InitializeCore: can't initialize builtins dict");
Expand All @@ -698,17 +709,6 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
/* initialize builtin exceptions */
_PyExc_Init(bimod);

sysmod = _PySys_BeginInit();
if (sysmod == NULL)
Py_FatalError("Py_InitializeCore: can't initialize sys");
interp->sysdict = PyModule_GetDict(sysmod);
if (interp->sysdict == NULL)
Py_FatalError("Py_InitializeCore: can't initialize sys dict");
Py_INCREF(interp->sysdict);
_PyImport_FixupBuiltin(sysmod, "sys");
PyDict_SetItemString(interp->sysdict, "modules",
interp->modules);

/* Set up a preliminary stderr printer until we have enough
infrastructure for the io module in place. */
pstderr = PyFile_NewStdPrinter(fileno(stderr));
Expand Down Expand Up @@ -1203,9 +1203,23 @@ Py_NewInterpreter(void)

/* XXX The following is lax in error checking */

interp->modules = PyDict_New();
PyObject *modules = PyDict_New();
if (modules == NULL)
Py_FatalError("Py_NewInterpreter: can't make modules dictionary");
interp->modules = modules;

bimod = _PyImport_FindBuiltin("builtins");
sysmod = _PyImport_FindBuiltin("sys", modules);
if (sysmod != NULL) {
interp->sysdict = PyModule_GetDict(sysmod);
if (interp->sysdict == NULL)
goto handle_error;
Py_INCREF(interp->sysdict);
PyDict_SetItemString(interp->sysdict, "modules", modules);
PySys_SetPath(Py_GetPath());
_PySys_EndInit(interp->sysdict);
}

bimod = _PyImport_FindBuiltin("builtins", modules);
if (bimod != NULL) {
interp->builtins = PyModule_GetDict(bimod);
if (interp->builtins == NULL)
Expand All @@ -1216,18 +1230,9 @@ Py_NewInterpreter(void)
/* initialize builtin exceptions */
_PyExc_Init(bimod);

sysmod = _PyImport_FindBuiltin("sys");
if (bimod != NULL && sysmod != NULL) {
PyObject *pstderr;

interp->sysdict = PyModule_GetDict(sysmod);
if (interp->sysdict == NULL)
goto handle_error;
Py_INCREF(interp->sysdict);
_PySys_EndInit(interp->sysdict);
PySys_SetPath(Py_GetPath());
PyDict_SetItemString(interp->sysdict, "modules",
interp->modules);
/* Set up a preliminary stderr printer until we have enough
infrastructure for the io module in place. */
pstderr = PyFile_NewStdPrinter(fileno(stderr));
Expand Down Expand Up @@ -1903,9 +1908,8 @@ wait_for_thread_shutdown(void)
{
_Py_IDENTIFIER(_shutdown);
PyObject *result;
PyThreadState *tstate = PyThreadState_GET();
PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
"threading");
PyObject *modules = PyImport_GetModuleDict();
PyObject *threading = PyMapping_GetItemString(modules, "threading");
if (threading == NULL) {
/* threading not imported */
PyErr_Clear();
Expand Down
Loading