bpo-1635741: Convert _imp to multi-phase init (GH-23378)
Convert the _imp extension module to the multi-phase initialization API (PEP 489). * Add _PyImport_BootstrapImp() which fix a bootstrap issue: import the _imp module before importlib is initialized. * Add create_builtin() sub-function, used by _imp_create_builtin(). * Initialize PyInterpreterState.import_func earlier, in pycore_init_builtins(). * Remove references to _PyImport_Cleanup(). This function has been renamed to finalize_modules() and moved to pylifecycle.c.
This commit is contained in:
parent
e0251787d8
commit
6223071421
|
@ -13,7 +13,7 @@ PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
|
||||||
#ifdef HAVE_FORK
|
#ifdef HAVE_FORK
|
||||||
extern PyStatus _PyImport_ReInitLock(void);
|
extern PyStatus _PyImport_ReInitLock(void);
|
||||||
#endif
|
#endif
|
||||||
extern void _PyImport_Cleanup(PyThreadState *tstate);
|
extern PyObject* _PyImport_BootstrapImp(PyThreadState *tstate);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -14501,7 +14501,7 @@ os__remove_dll_directory_impl(PyObject *module, PyObject *cookie)
|
||||||
|
|
||||||
os.waitstatus_to_exitcode() is implemented in C and not in Python, so
|
os.waitstatus_to_exitcode() is implemented in C and not in Python, so
|
||||||
subprocess can safely call it during late Python finalization without
|
subprocess can safely call it during late Python finalization without
|
||||||
risking that used os attributes were set to None by _PyImport_Cleanup(). */
|
risking that used os attributes were set to None by finalize_modules(). */
|
||||||
#if defined(WIFEXITED) || defined(MS_WINDOWS)
|
#if defined(WIFEXITED) || defined(MS_WINDOWS)
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
os.waitstatus_to_exitcode
|
os.waitstatus_to_exitcode
|
||||||
|
|
209
Python/import.c
209
Python/import.c
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "Python-ast.h"
|
#include "Python-ast.h"
|
||||||
#undef Yield /* undefine macro conflicting with <winbase.h> */
|
#undef Yield /* undefine macro conflicting with <winbase.h> */
|
||||||
|
#include "pycore_import.h" // _PyImport_BootstrapImp()
|
||||||
#include "pycore_initconfig.h"
|
#include "pycore_initconfig.h"
|
||||||
#include "pycore_pyerrors.h"
|
#include "pycore_pyerrors.h"
|
||||||
#include "pycore_pyhash.h"
|
#include "pycore_pyhash.h"
|
||||||
|
@ -978,6 +979,54 @@ PyImport_GetImporter(PyObject *path)
|
||||||
return importer;
|
return importer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
|
||||||
|
{
|
||||||
|
PyObject *mod = _PyImport_FindExtensionObject(name, name);
|
||||||
|
if (mod || _PyErr_Occurred(tstate)) {
|
||||||
|
Py_XINCREF(mod);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *modules = tstate->interp->modules;
|
||||||
|
for (struct _inittab *p = PyImport_Inittab; p->name != NULL; p++) {
|
||||||
|
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
|
||||||
|
if (p->initfunc == NULL) {
|
||||||
|
/* Cannot re-init internal module ("sys" or "builtins") */
|
||||||
|
return PyImport_AddModuleObject(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = (*p->initfunc)();
|
||||||
|
if (mod == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
|
||||||
|
return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Remember pointer to module init function. */
|
||||||
|
PyModuleDef *def = PyModule_GetDef(mod);
|
||||||
|
if (def == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
def->m_base.m_init = p->initfunc;
|
||||||
|
if (_PyImport_FixupExtensionObject(mod, name, name,
|
||||||
|
modules) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not found
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
_imp.create_builtin
|
_imp.create_builtin
|
||||||
|
|
||||||
|
@ -992,68 +1041,16 @@ _imp_create_builtin(PyObject *module, PyObject *spec)
|
||||||
/*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/
|
/*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
struct _inittab *p;
|
|
||||||
PyObject *name;
|
|
||||||
const char *namestr;
|
|
||||||
PyObject *mod;
|
|
||||||
|
|
||||||
name = PyObject_GetAttrString(spec, "name");
|
PyObject *name = PyObject_GetAttrString(spec, "name");
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = _PyImport_FindExtensionObject(name, name);
|
PyObject *mod = create_builtin(tstate, name, spec);
|
||||||
if (mod || _PyErr_Occurred(tstate)) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
Py_XINCREF(mod);
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
namestr = PyUnicode_AsUTF8(name);
|
|
||||||
if (namestr == NULL) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *modules = tstate->interp->modules;
|
|
||||||
for (p = PyImport_Inittab; p->name != NULL; p++) {
|
|
||||||
PyModuleDef *def;
|
|
||||||
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
|
|
||||||
if (p->initfunc == NULL) {
|
|
||||||
/* Cannot re-init internal module ("sys" or "builtins") */
|
|
||||||
mod = PyImport_AddModule(namestr);
|
|
||||||
Py_DECREF(name);
|
Py_DECREF(name);
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
mod = (*p->initfunc)();
|
|
||||||
if (mod == NULL) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec);
|
|
||||||
} else {
|
|
||||||
/* Remember pointer to module init function. */
|
|
||||||
def = PyModule_GetDef(mod);
|
|
||||||
if (def == NULL) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
def->m_base.m_init = p->initfunc;
|
|
||||||
if (_PyImport_FixupExtensionObject(mod, name, name,
|
|
||||||
modules) < 0) {
|
|
||||||
Py_DECREF(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_DECREF(name);
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Py_DECREF(name);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Frozen modules */
|
/* Frozen modules */
|
||||||
|
@ -2127,46 +2124,88 @@ static PyMethodDef imp_methods[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct PyModuleDef impmodule = {
|
static int
|
||||||
|
imp_module_exec(PyObject *module)
|
||||||
|
{
|
||||||
|
const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode;
|
||||||
|
PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1);
|
||||||
|
if (pyc_mode == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (PyModule_AddObjectRef(module, "check_hash_based_pycs", pyc_mode) < 0) {
|
||||||
|
Py_DECREF(pyc_mode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Py_DECREF(pyc_mode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyModuleDef_Slot imp_slots[] = {
|
||||||
|
{Py_mod_exec, imp_module_exec},
|
||||||
|
{0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef imp_module = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_imp",
|
.m_name = "_imp",
|
||||||
doc_imp,
|
.m_doc = doc_imp,
|
||||||
0,
|
.m_size = 0,
|
||||||
imp_methods,
|
.m_methods = imp_methods,
|
||||||
NULL,
|
.m_slots = imp_slots,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit__imp(void)
|
PyInit__imp(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *d;
|
return PyModuleDef_Init(&imp_module);
|
||||||
|
|
||||||
m = PyModule_Create(&impmodule);
|
|
||||||
if (m == NULL) {
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
d = PyModule_GetDict(m);
|
|
||||||
if (d == NULL) {
|
|
||||||
goto failure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode;
|
|
||||||
PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1);
|
|
||||||
if (pyc_mode == NULL) {
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
if (PyDict_SetItemString(d, "check_hash_based_pycs", pyc_mode) < 0) {
|
|
||||||
Py_DECREF(pyc_mode);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
Py_DECREF(pyc_mode);
|
|
||||||
|
|
||||||
return m;
|
// Import the _imp extension by calling manually _imp.create_builtin() and
|
||||||
failure:
|
// _imp.exec_builtin() since importlib is not initialized yet. Initializing
|
||||||
Py_XDECREF(m);
|
// importlib requires the _imp module: this function fix the bootstrap issue.
|
||||||
|
PyObject*
|
||||||
|
_PyImport_BootstrapImp(PyThreadState *tstate)
|
||||||
|
{
|
||||||
|
PyObject *name = PyUnicode_FromString("_imp");
|
||||||
|
if (name == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock a ModuleSpec object just good enough for PyModule_FromDefAndSpec():
|
||||||
|
// an object with just a name attribute.
|
||||||
|
//
|
||||||
|
// _imp.__spec__ is overriden by importlib._bootstrap._instal() anyway.
|
||||||
|
PyObject *attrs = Py_BuildValue("{sO}", "name", name);
|
||||||
|
if (attrs == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
PyObject *spec = _PyNamespace_New(attrs);
|
||||||
|
Py_DECREF(attrs);
|
||||||
|
if (spec == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the _imp module from its definition.
|
||||||
|
PyObject *mod = create_builtin(tstate, name, spec);
|
||||||
|
Py_CLEAR(name);
|
||||||
|
Py_DECREF(spec);
|
||||||
|
if (mod == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
assert(mod != Py_None); // not found
|
||||||
|
|
||||||
|
// Execute the _imp module: call imp_module_exec().
|
||||||
|
if (exec_builtin_or_dynamic(mod) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "pycore_ceval.h" // _PyEval_FiniGIL()
|
#include "pycore_ceval.h" // _PyEval_FiniGIL()
|
||||||
#include "pycore_context.h" // _PyContext_Init()
|
#include "pycore_context.h" // _PyContext_Init()
|
||||||
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
|
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
|
||||||
|
#include "pycore_import.h" // _PyImport_BootstrapImp()
|
||||||
#include "pycore_initconfig.h" // _PyStatus_OK()
|
#include "pycore_initconfig.h" // _PyStatus_OK()
|
||||||
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
|
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
|
||||||
#include "pycore_pathconfig.h" // _PyConfig_WritePathConfig()
|
#include "pycore_pathconfig.h" // _PyConfig_WritePathConfig()
|
||||||
|
@ -155,18 +156,11 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod)
|
||||||
}
|
}
|
||||||
interp->importlib = Py_NewRef(importlib);
|
interp->importlib = Py_NewRef(importlib);
|
||||||
|
|
||||||
PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
|
|
||||||
"__import__");
|
|
||||||
if (import_func == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
interp->import_func = Py_NewRef(import_func);
|
|
||||||
|
|
||||||
// Import the _imp module
|
// Import the _imp module
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PySys_FormatStderr("import _imp # builtin\n");
|
PySys_FormatStderr("import _imp # builtin\n");
|
||||||
}
|
}
|
||||||
PyObject *imp_mod = PyInit__imp();
|
PyObject *imp_mod = _PyImport_BootstrapImp(tstate);
|
||||||
if (imp_mod == NULL) {
|
if (imp_mod == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -741,6 +735,14 @@ pycore_init_builtins(PyThreadState *tstate)
|
||||||
}
|
}
|
||||||
Py_DECREF(bimod);
|
Py_DECREF(bimod);
|
||||||
|
|
||||||
|
// Get the __import__ function
|
||||||
|
PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
|
||||||
|
"__import__");
|
||||||
|
if (import_func == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
interp->import_func = Py_NewRef(import_func);
|
||||||
|
|
||||||
assert(!_PyErr_Occurred(tstate));
|
assert(!_PyErr_Occurred(tstate));
|
||||||
|
|
||||||
return _PyStatus_OK();
|
return _PyStatus_OK();
|
||||||
|
|
Loading…
Reference in New Issue