Skip to content

Commit 2a91353

Browse files
Let the caller of update_extensions_cache() decide if m_copy should be populated.
1 parent 8b4e216 commit 2a91353

File tree

1 file changed

+86
-19
lines changed

1 file changed

+86
-19
lines changed

Python/import.c

Lines changed: 86 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,19 +1185,48 @@ is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *path)
11851185
return 0;
11861186
}
11871187

1188+
#ifndef NDEBUG
1189+
static bool
1190+
is_singlephase(PyModuleDef *def)
1191+
{
1192+
if (def == NULL) {
1193+
/* It must be a module created by reload_singlephase_extension()
1194+
* from m_copy. Ideally we'd do away with this case. */
1195+
return true;
1196+
}
1197+
else if (def->m_slots == NULL) {
1198+
return true;
1199+
}
1200+
else {
1201+
return false;
1202+
}
1203+
}
1204+
#endif
1205+
1206+
1207+
struct singlephase_global_update {
1208+
PyObject *m_dict;
1209+
};
11881210

11891211
static int
11901212
update_global_state_for_extension(PyThreadState *tstate,
1191-
PyObject *mod, PyModuleDef *def,
1192-
PyObject *name, PyObject *path)
1213+
PyObject *path, PyObject *name,
1214+
PyModuleDef *def,
1215+
struct singlephase_global_update *singlephase)
11931216
{
1194-
assert(mod != NULL && PyModule_Check(mod));
1195-
assert(def == _PyModule_GetDef(mod));
1196-
1197-
// bpo-44050: Extensions and def->m_base.m_copy can be updated
1198-
// when the extension module doesn't support sub-interpreters.
1199-
if (def->m_size == -1) {
1200-
if (!is_core_module(tstate->interp, name, path)) {
1217+
/* Copy the module's __dict__, if applicable. */
1218+
if (singlephase == NULL) {
1219+
assert(def->m_base.m_copy == NULL);
1220+
}
1221+
else {
1222+
assert(def->m_base.m_init != NULL
1223+
|| is_core_module(tstate->interp, name, path));
1224+
if (singlephase->m_dict != NULL) {
1225+
assert(PyDict_Check(singlephase->m_dict));
1226+
// gh-88216: Extensions and def->m_base.m_copy can be updated
1227+
// when the extension module doesn't support sub-interpreters.
1228+
assert(def->m_size == -1);
1229+
assert(!is_core_module(tstate->interp, name, path));
12011230
assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0);
12021231
assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0);
12031232
if (def->m_base.m_copy) {
@@ -1206,17 +1235,16 @@ update_global_state_for_extension(PyThreadState *tstate,
12061235
XXX this should really not happen. */
12071236
Py_CLEAR(def->m_base.m_copy);
12081237
}
1209-
PyObject *dict = PyModule_GetDict(mod);
1210-
if (dict == NULL) {
1211-
return -1;
1212-
}
1213-
def->m_base.m_copy = PyDict_Copy(dict);
1238+
def->m_base.m_copy = PyDict_Copy(singlephase->m_dict);
12141239
if (def->m_base.m_copy == NULL) {
1240+
// XXX Ignore this error? Doing so would effectively
1241+
// mark the module as not loadable. */
12151242
return -1;
12161243
}
12171244
}
12181245
}
12191246

1247+
/* Add the module's def to the global cache. */
12201248
// XXX Why special-case the main interpreter?
12211249
if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) {
12221250
#ifndef NDEBUG
@@ -1268,15 +1296,27 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
12681296
return -1;
12691297
}
12701298

1299+
/* Only single-phase init extension modules can reach here. */
1300+
assert(is_singlephase(def));
1301+
12711302
PyThreadState *tstate = _PyThreadState_GET();
1303+
struct singlephase_global_update singlephase = {0};
1304+
// gh-88216: Extensions and def->m_base.m_copy can be updated
1305+
// when the extension module doesn't support sub-interpreters.
1306+
if (def->m_size == -1) {
1307+
singlephase.m_dict = PyModule_GetDict(mod);
1308+
assert(singlephase.m_dict != NULL);
1309+
}
12721310
if (update_global_state_for_extension(
1273-
tstate, mod, def, name, filename) < 0)
1311+
tstate, name, name, def, &singlephase) < 0)
12741312
{
12751313
return -1;
12761314
}
1315+
12771316
if (finish_singlephase_extension(tstate, mod, def, name, modules) < 0) {
12781317
return -1;
12791318
}
1319+
12801320
return 0;
12811321
}
12821322

@@ -1407,11 +1447,25 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
14071447
goto finally;
14081448
}
14091449

1450+
/* We only use _PyImport_FixupBuiltin() for the core builtin modules
1451+
* (sys and builtins). These modules are single-phase init with no
1452+
* module state, but we also don't populate def->m_base.m_copy
1453+
* for them. */
1454+
assert(is_core_module(tstate->interp, nameobj, nameobj));
1455+
assert(is_singlephase(def));
1456+
assert(def->m_size == -1);
1457+
assert(def->m_base.m_copy == NULL);
1458+
1459+
struct singlephase_global_update singlephase = {
1460+
/* We don't want def->m_base.m_copy populated. */
1461+
.m_dict=NULL,
1462+
};
14101463
if (update_global_state_for_extension(
1411-
tstate, mod, def, nameobj, nameobj) < 0)
1464+
tstate, nameobj, nameobj, def, &singlephase) < 0)
14121465
{
14131466
goto finally;
14141467
}
1468+
14151469
if (finish_singlephase_extension(tstate, mod, def, nameobj, modules) < 0) {
14161470
goto finally;
14171471
}
@@ -1444,6 +1498,7 @@ is_builtin(PyObject *name)
14441498
static PyObject*
14451499
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
14461500
{
1501+
PyModuleDef *def = NULL;
14471502
PyObject *mod = import_find_extension(tstate, name, name);
14481503
if (mod || _PyErr_Occurred(tstate)) {
14491504
return mod;
@@ -1473,20 +1528,32 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
14731528
}
14741529

14751530
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
1476-
return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec);
1531+
def = (PyModuleDef*)mod;
1532+
assert(!is_singlephase(def));
1533+
return PyModule_FromDefAndSpec(def, spec);
14771534
}
14781535
else {
14791536
assert(PyModule_Check(mod));
1480-
PyModuleDef *def = PyModule_GetDef(mod);
1537+
def = PyModule_GetDef(mod);
14811538
if (def == NULL) {
14821539
return NULL;
14831540
}
1541+
assert(is_singlephase(def));
14841542

14851543
/* Remember pointer to module init function. */
14861544
def->m_base.m_init = p0;
14871545

1546+
struct singlephase_global_update singlephase = {0};
1547+
// gh-88216: Extensions and def->m_base.m_copy can be updated
1548+
// when the extension module doesn't support sub-interpreters.
1549+
if (def->m_size == -1
1550+
&& !is_core_module(tstate->interp, name, name))
1551+
{
1552+
singlephase.m_dict = PyModule_GetDict(mod);
1553+
assert(singlephase.m_dict != NULL);
1554+
}
14881555
if (update_global_state_for_extension(
1489-
tstate, mod, def, name, name) < 0)
1556+
tstate, name, name, def, &singlephase) < 0)
14901557
{
14911558
return NULL;
14921559
}

0 commit comments

Comments
 (0)