Skip to content

Commit cdb21ba

Browse files
gh-102660: Handle m_copy Specially for the sys and builtins Modules (gh-102661)
It doesn't make sense to use multi-phase init for these modules. Using a per-interpreter "m_copy" (instead of PyModuleDef.m_base.m_copy) makes this work okay. (This came up while working on gh-101660.) Note that we might instead end up disallowing re-load for sys/builtins since they are so special. #102660
1 parent 80abd62 commit cdb21ba

File tree

5 files changed

+44
-4
lines changed

5 files changed

+44
-4
lines changed

Include/internal/pycore_interp.h

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ struct _is {
111111

112112
PyObject *dict; /* Stores per-interpreter state */
113113

114+
PyObject *sysdict_copy;
114115
PyObject *builtins_copy;
115116
// Initialized to _PyEval_EvalFrameDefault().
116117
_PyFrameEvalFunction eval_frame;

Python/bltinmodule.c

+3
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,9 @@ _PyBuiltin_Init(PyInterpreterState *interp)
30983098
}
30993099
Py_DECREF(debug);
31003100

3101+
/* m_copy of Py_None means it is copied some other way. */
3102+
builtinsmodule.m_base.m_copy = Py_NewRef(Py_None);
3103+
31013104
return mod;
31023105
#undef ADD_TO_ALL
31033106
#undef SETBUILTIN

Python/import.c

+31-4
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,16 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name)
978978
return 0;
979979
}
980980

981+
static inline int
982+
match_mod_name(PyObject *actual, const char *expected)
983+
{
984+
if (PyUnicode_CompareWithASCIIString(actual, expected) == 0) {
985+
return 1;
986+
}
987+
assert(!PyErr_Occurred());
988+
return 0;
989+
}
990+
981991
static int
982992
fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename)
983993
{
@@ -1001,7 +1011,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename)
10011011
// when the extension module doesn't support sub-interpreters.
10021012
// XXX Why special-case the main interpreter?
10031013
if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) {
1004-
if (def->m_size == -1) {
1014+
/* m_copy of Py_None means it is copied some other way. */
1015+
if (def->m_size == -1 && def->m_base.m_copy != Py_None) {
10051016
if (def->m_base.m_copy) {
10061017
/* Somebody already imported the module,
10071018
likely under a different name.
@@ -1055,18 +1066,34 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
10551066
PyObject *modules = MODULES(tstate->interp);
10561067

10571068
if (def->m_size == -1) {
1069+
PyObject *m_copy = def->m_base.m_copy;
10581070
/* Module does not support repeated initialization */
1059-
if (def->m_base.m_copy == NULL)
1071+
if (m_copy == NULL) {
10601072
return NULL;
1073+
}
1074+
else if (m_copy == Py_None) {
1075+
if (match_mod_name(name, "sys")) {
1076+
m_copy = tstate->interp->sysdict_copy;
1077+
}
1078+
else if (match_mod_name(name, "builtins")) {
1079+
m_copy = tstate->interp->builtins_copy;
1080+
}
1081+
else {
1082+
_PyErr_SetString(tstate, PyExc_ImportError, "missing m_copy");
1083+
return NULL;
1084+
}
1085+
}
1086+
/* m_copy of Py_None means it is copied some other way. */
10611087
mod = import_add_module(tstate, name);
1062-
if (mod == NULL)
1088+
if (mod == NULL) {
10631089
return NULL;
1090+
}
10641091
mdict = PyModule_GetDict(mod);
10651092
if (mdict == NULL) {
10661093
Py_DECREF(mod);
10671094
return NULL;
10681095
}
1069-
if (PyDict_Update(mdict, def->m_base.m_copy)) {
1096+
if (PyDict_Update(mdict, m_copy)) {
10701097
Py_DECREF(mod);
10711098
return NULL;
10721099
}

Python/pystate.c

+1
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
805805
assert(interp->imports.importlib == NULL);
806806
assert(interp->imports.import_func == NULL);
807807

808+
Py_CLEAR(interp->sysdict_copy);
808809
Py_CLEAR(interp->builtins_copy);
809810
Py_CLEAR(interp->dict);
810811
#ifdef HAVE_FORK

Python/sysmodule.c

+8
Original file line numberDiff line numberDiff line change
@@ -3425,12 +3425,20 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p)
34253425
return _PyStatus_ERR("failed to create a module object");
34263426
}
34273427

3428+
/* m_copy of Py_None means it is copied some other way. */
3429+
sysmodule.m_base.m_copy = Py_NewRef(Py_None);
3430+
34283431
PyObject *sysdict = PyModule_GetDict(sysmod);
34293432
if (sysdict == NULL) {
34303433
goto error;
34313434
}
34323435
interp->sysdict = Py_NewRef(sysdict);
34333436

3437+
interp->sysdict_copy = PyDict_Copy(sysdict);
3438+
if (interp->sysdict_copy == NULL) {
3439+
goto error;
3440+
}
3441+
34343442
if (PyDict_SetItemString(sysdict, "modules", modules) < 0) {
34353443
goto error;
34363444
}

0 commit comments

Comments
 (0)