@@ -1185,19 +1185,48 @@ is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *path)
1185
1185
return 0 ;
1186
1186
}
1187
1187
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
+ };
1188
1210
1189
1211
static int
1190
1212
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 )
1193
1216
{
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 ));
1201
1230
assert (PyUnicode_CompareWithASCIIString (name , "sys" ) != 0 );
1202
1231
assert (PyUnicode_CompareWithASCIIString (name , "builtins" ) != 0 );
1203
1232
if (def -> m_base .m_copy ) {
@@ -1206,17 +1235,16 @@ update_global_state_for_extension(PyThreadState *tstate,
1206
1235
XXX this should really not happen. */
1207
1236
Py_CLEAR (def -> m_base .m_copy );
1208
1237
}
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 );
1214
1239
if (def -> m_base .m_copy == NULL ) {
1240
+ // XXX Ignore this error? Doing so would effectively
1241
+ // mark the module as not loadable. */
1215
1242
return -1 ;
1216
1243
}
1217
1244
}
1218
1245
}
1219
1246
1247
+ /* Add the module's def to the global cache. */
1220
1248
// XXX Why special-case the main interpreter?
1221
1249
if (_Py_IsMainInterpreter (tstate -> interp ) || def -> m_size == -1 ) {
1222
1250
#ifndef NDEBUG
@@ -1268,15 +1296,27 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
1268
1296
return -1 ;
1269
1297
}
1270
1298
1299
+ /* Only single-phase init extension modules can reach here. */
1300
+ assert (is_singlephase (def ));
1301
+
1271
1302
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
+ }
1272
1310
if (update_global_state_for_extension (
1273
- tstate , mod , def , name , filename ) < 0 )
1311
+ tstate , name , name , def , & singlephase ) < 0 )
1274
1312
{
1275
1313
return -1 ;
1276
1314
}
1315
+
1277
1316
if (finish_singlephase_extension (tstate , mod , def , name , modules ) < 0 ) {
1278
1317
return -1 ;
1279
1318
}
1319
+
1280
1320
return 0 ;
1281
1321
}
1282
1322
@@ -1407,11 +1447,25 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
1407
1447
goto finally ;
1408
1448
}
1409
1449
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
+ };
1410
1463
if (update_global_state_for_extension (
1411
- tstate , mod , def , nameobj , nameobj ) < 0 )
1464
+ tstate , nameobj , nameobj , def , & singlephase ) < 0 )
1412
1465
{
1413
1466
goto finally ;
1414
1467
}
1468
+
1415
1469
if (finish_singlephase_extension (tstate , mod , def , nameobj , modules ) < 0 ) {
1416
1470
goto finally ;
1417
1471
}
@@ -1444,6 +1498,7 @@ is_builtin(PyObject *name)
1444
1498
static PyObject *
1445
1499
create_builtin (PyThreadState * tstate , PyObject * name , PyObject * spec )
1446
1500
{
1501
+ PyModuleDef * def = NULL ;
1447
1502
PyObject * mod = import_find_extension (tstate , name , name );
1448
1503
if (mod || _PyErr_Occurred (tstate )) {
1449
1504
return mod ;
@@ -1473,20 +1528,32 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
1473
1528
}
1474
1529
1475
1530
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 );
1477
1534
}
1478
1535
else {
1479
1536
assert (PyModule_Check (mod ));
1480
- PyModuleDef * def = PyModule_GetDef (mod );
1537
+ def = PyModule_GetDef (mod );
1481
1538
if (def == NULL ) {
1482
1539
return NULL ;
1483
1540
}
1541
+ assert (is_singlephase (def ));
1484
1542
1485
1543
/* Remember pointer to module init function. */
1486
1544
def -> m_base .m_init = p0 ;
1487
1545
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
+ }
1488
1555
if (update_global_state_for_extension (
1489
- tstate , mod , def , name , name ) < 0 )
1556
+ tstate , name , name , def , & singlephase ) < 0 )
1490
1557
{
1491
1558
return NULL ;
1492
1559
}
0 commit comments