Skip to content

Commit 6223071

Browse files
authored
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.
1 parent e025178 commit 6223071

File tree

4 files changed

+122
-81
lines changed

4 files changed

+122
-81
lines changed

Include/internal/pycore_import.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ PyAPI_FUNC(PyObject *) _PyImport_FindBuiltin(
1313
#ifdef HAVE_FORK
1414
extern PyStatus _PyImport_ReInitLock(void);
1515
#endif
16-
extern void _PyImport_Cleanup(PyThreadState *tstate);
16+
extern PyObject* _PyImport_BootstrapImp(PyThreadState *tstate);
1717

1818
#ifdef __cplusplus
1919
}

Modules/posixmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14501,7 +14501,7 @@ os__remove_dll_directory_impl(PyObject *module, PyObject *cookie)
1450114501
1450214502
os.waitstatus_to_exitcode() is implemented in C and not in Python, so
1450314503
subprocess can safely call it during late Python finalization without
14504-
risking that used os attributes were set to None by _PyImport_Cleanup(). */
14504+
risking that used os attributes were set to None by finalize_modules(). */
1450514505
#if defined(WIFEXITED) || defined(MS_WINDOWS)
1450614506
/*[clinic input]
1450714507
os.waitstatus_to_exitcode

Python/import.c

Lines changed: 110 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "Python-ast.h"
66
#undef Yield /* undefine macro conflicting with <winbase.h> */
7+
#include "pycore_import.h" // _PyImport_BootstrapImp()
78
#include "pycore_initconfig.h"
89
#include "pycore_pyerrors.h"
910
#include "pycore_pyhash.h"
@@ -978,84 +979,80 @@ PyImport_GetImporter(PyObject *path)
978979
return importer;
979980
}
980981

981-
/*[clinic input]
982-
_imp.create_builtin
983-
984-
spec: object
985-
/
986-
987-
Create an extension module.
988-
[clinic start generated code]*/
989-
990-
static PyObject *
991-
_imp_create_builtin(PyObject *module, PyObject *spec)
992-
/*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/
982+
static PyObject*
983+
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
993984
{
994-
PyThreadState *tstate = _PyThreadState_GET();
995-
struct _inittab *p;
996-
PyObject *name;
997-
const char *namestr;
998-
PyObject *mod;
999-
1000-
name = PyObject_GetAttrString(spec, "name");
1001-
if (name == NULL) {
1002-
return NULL;
1003-
}
1004-
1005-
mod = _PyImport_FindExtensionObject(name, name);
985+
PyObject *mod = _PyImport_FindExtensionObject(name, name);
1006986
if (mod || _PyErr_Occurred(tstate)) {
1007-
Py_DECREF(name);
1008987
Py_XINCREF(mod);
1009988
return mod;
1010989
}
1011990

1012-
namestr = PyUnicode_AsUTF8(name);
1013-
if (namestr == NULL) {
1014-
Py_DECREF(name);
1015-
return NULL;
1016-
}
1017-
1018991
PyObject *modules = tstate->interp->modules;
1019-
for (p = PyImport_Inittab; p->name != NULL; p++) {
1020-
PyModuleDef *def;
992+
for (struct _inittab *p = PyImport_Inittab; p->name != NULL; p++) {
1021993
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
1022994
if (p->initfunc == NULL) {
1023995
/* Cannot re-init internal module ("sys" or "builtins") */
1024-
mod = PyImport_AddModule(namestr);
1025-
Py_DECREF(name);
1026-
return mod;
996+
return PyImport_AddModuleObject(name);
1027997
}
998+
1028999
mod = (*p->initfunc)();
10291000
if (mod == NULL) {
1030-
Py_DECREF(name);
10311001
return NULL;
10321002
}
1003+
10331004
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
1034-
Py_DECREF(name);
10351005
return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec);
1036-
} else {
1006+
}
1007+
else {
10371008
/* Remember pointer to module init function. */
1038-
def = PyModule_GetDef(mod);
1009+
PyModuleDef *def = PyModule_GetDef(mod);
10391010
if (def == NULL) {
1040-
Py_DECREF(name);
10411011
return NULL;
10421012
}
1013+
10431014
def->m_base.m_init = p->initfunc;
10441015
if (_PyImport_FixupExtensionObject(mod, name, name,
10451016
modules) < 0) {
1046-
Py_DECREF(name);
10471017
return NULL;
10481018
}
1049-
Py_DECREF(name);
10501019
return mod;
10511020
}
10521021
}
10531022
}
1054-
Py_DECREF(name);
1023+
1024+
// not found
10551025
Py_RETURN_NONE;
10561026
}
10571027

10581028

1029+
1030+
/*[clinic input]
1031+
_imp.create_builtin
1032+
1033+
spec: object
1034+
/
1035+
1036+
Create an extension module.
1037+
[clinic start generated code]*/
1038+
1039+
static PyObject *
1040+
_imp_create_builtin(PyObject *module, PyObject *spec)
1041+
/*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/
1042+
{
1043+
PyThreadState *tstate = _PyThreadState_GET();
1044+
1045+
PyObject *name = PyObject_GetAttrString(spec, "name");
1046+
if (name == NULL) {
1047+
return NULL;
1048+
}
1049+
1050+
PyObject *mod = create_builtin(tstate, name, spec);
1051+
Py_DECREF(name);
1052+
return mod;
1053+
}
1054+
1055+
10591056
/* Frozen modules */
10601057

10611058
static const struct _frozen *
@@ -2127,46 +2124,88 @@ static PyMethodDef imp_methods[] = {
21272124
};
21282125

21292126

2130-
static struct PyModuleDef impmodule = {
2127+
static int
2128+
imp_module_exec(PyObject *module)
2129+
{
2130+
const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode;
2131+
PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1);
2132+
if (pyc_mode == NULL) {
2133+
return -1;
2134+
}
2135+
if (PyModule_AddObjectRef(module, "check_hash_based_pycs", pyc_mode) < 0) {
2136+
Py_DECREF(pyc_mode);
2137+
return -1;
2138+
}
2139+
Py_DECREF(pyc_mode);
2140+
2141+
return 0;
2142+
}
2143+
2144+
2145+
static PyModuleDef_Slot imp_slots[] = {
2146+
{Py_mod_exec, imp_module_exec},
2147+
{0, NULL}
2148+
};
2149+
2150+
static struct PyModuleDef imp_module = {
21312151
PyModuleDef_HEAD_INIT,
2132-
"_imp",
2133-
doc_imp,
2134-
0,
2135-
imp_methods,
2136-
NULL,
2137-
NULL,
2138-
NULL,
2139-
NULL
2152+
.m_name = "_imp",
2153+
.m_doc = doc_imp,
2154+
.m_size = 0,
2155+
.m_methods = imp_methods,
2156+
.m_slots = imp_slots,
21402157
};
21412158

21422159
PyMODINIT_FUNC
21432160
PyInit__imp(void)
21442161
{
2145-
PyObject *m, *d;
2162+
return PyModuleDef_Init(&imp_module);
2163+
}
21462164

2147-
m = PyModule_Create(&impmodule);
2148-
if (m == NULL) {
2149-
goto failure;
2165+
2166+
// Import the _imp extension by calling manually _imp.create_builtin() and
2167+
// _imp.exec_builtin() since importlib is not initialized yet. Initializing
2168+
// importlib requires the _imp module: this function fix the bootstrap issue.
2169+
PyObject*
2170+
_PyImport_BootstrapImp(PyThreadState *tstate)
2171+
{
2172+
PyObject *name = PyUnicode_FromString("_imp");
2173+
if (name == NULL) {
2174+
return NULL;
21502175
}
2151-
d = PyModule_GetDict(m);
2152-
if (d == NULL) {
2153-
goto failure;
2176+
2177+
// Mock a ModuleSpec object just good enough for PyModule_FromDefAndSpec():
2178+
// an object with just a name attribute.
2179+
//
2180+
// _imp.__spec__ is overriden by importlib._bootstrap._instal() anyway.
2181+
PyObject *attrs = Py_BuildValue("{sO}", "name", name);
2182+
if (attrs == NULL) {
2183+
goto error;
2184+
}
2185+
PyObject *spec = _PyNamespace_New(attrs);
2186+
Py_DECREF(attrs);
2187+
if (spec == NULL) {
2188+
goto error;
21542189
}
21552190

2156-
const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode;
2157-
PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1);
2158-
if (pyc_mode == NULL) {
2159-
goto failure;
2191+
// Create the _imp module from its definition.
2192+
PyObject *mod = create_builtin(tstate, name, spec);
2193+
Py_CLEAR(name);
2194+
Py_DECREF(spec);
2195+
if (mod == NULL) {
2196+
goto error;
21602197
}
2161-
if (PyDict_SetItemString(d, "check_hash_based_pycs", pyc_mode) < 0) {
2162-
Py_DECREF(pyc_mode);
2163-
goto failure;
2198+
assert(mod != Py_None); // not found
2199+
2200+
// Execute the _imp module: call imp_module_exec().
2201+
if (exec_builtin_or_dynamic(mod) < 0) {
2202+
Py_DECREF(mod);
2203+
goto error;
21642204
}
2165-
Py_DECREF(pyc_mode);
2205+
return mod;
21662206

2167-
return m;
2168-
failure:
2169-
Py_XDECREF(m);
2207+
error:
2208+
Py_XDECREF(name);
21702209
return NULL;
21712210
}
21722211

Python/pylifecycle.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "pycore_ceval.h" // _PyEval_FiniGIL()
99
#include "pycore_context.h" // _PyContext_Init()
1010
#include "pycore_fileutils.h" // _Py_ResetForceASCII()
11+
#include "pycore_import.h" // _PyImport_BootstrapImp()
1112
#include "pycore_initconfig.h" // _PyStatus_OK()
1213
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
1314
#include "pycore_pathconfig.h" // _PyConfig_WritePathConfig()
@@ -155,18 +156,11 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod)
155156
}
156157
interp->importlib = Py_NewRef(importlib);
157158

158-
PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
159-
"__import__");
160-
if (import_func == NULL) {
161-
return -1;
162-
}
163-
interp->import_func = Py_NewRef(import_func);
164-
165159
// Import the _imp module
166160
if (verbose) {
167161
PySys_FormatStderr("import _imp # builtin\n");
168162
}
169-
PyObject *imp_mod = PyInit__imp();
163+
PyObject *imp_mod = _PyImport_BootstrapImp(tstate);
170164
if (imp_mod == NULL) {
171165
return -1;
172166
}
@@ -741,6 +735,14 @@ pycore_init_builtins(PyThreadState *tstate)
741735
}
742736
Py_DECREF(bimod);
743737

738+
// Get the __import__ function
739+
PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
740+
"__import__");
741+
if (import_func == NULL) {
742+
goto error;
743+
}
744+
interp->import_func = Py_NewRef(import_func);
745+
744746
assert(!_PyErr_Occurred(tstate));
745747

746748
return _PyStatus_OK();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy