@@ -1193,26 +1193,63 @@ is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *path)
1193
1193
}
1194
1194
1195
1195
#ifndef NDEBUG
1196
- static bool
1197
- is_singlephase (PyModuleDef * def )
1196
+ static _Py_ext_module_kind
1197
+ _get_extension_kind (PyModuleDef * def , bool check_size )
1198
1198
{
1199
+ _Py_ext_module_kind kind ;
1199
1200
if (def == NULL ) {
1200
1201
/* It must be a module created by reload_singlephase_extension()
1201
1202
* from m_copy. Ideally we'd do away with this case. */
1202
- return true ;
1203
+ kind = _Py_ext_module_kind_SINGLEPHASE ;
1203
1204
}
1204
- else if (def -> m_slots = = NULL ) {
1205
- return true ;
1205
+ else if (def -> m_slots ! = NULL ) {
1206
+ kind = _Py_ext_module_kind_MULTIPHASE ;
1206
1207
}
1207
- else {
1208
- return false ;
1208
+ else if ( check_size && def -> m_size == -1 ) {
1209
+ kind = _Py_ext_module_kind_SINGLEPHASE ;
1209
1210
}
1210
- }
1211
+ else if (def -> m_base .m_init != NULL ) {
1212
+ kind = _Py_ext_module_kind_SINGLEPHASE ;
1213
+ }
1214
+ else {
1215
+ // This is probably single-phase init, but a multi-phase
1216
+ // module *can* have NULL m_slots.
1217
+ kind = _Py_ext_module_kind_UNKNOWN ;
1218
+ }
1219
+ return kind ;
1220
+ }
1221
+
1222
+ /* The module might not be fully initialized yet
1223
+ * and PyModule_FromDefAndSpec() checks m_size
1224
+ * so we skip m_size. */
1225
+ #define assert_multiphase_def (def ) \
1226
+ do { \
1227
+ _Py_ext_module_kind kind = _get_extension_kind(def, false); \
1228
+ assert(kind == _Py_ext_module_kind_MULTIPHASE \
1229
+ /* m_slots can be NULL. */ \
1230
+ || kind == _Py_ext_module_kind_UNKNOWN); \
1231
+ } while (0)
1232
+
1233
+ #define assert_singlephase_def (def ) \
1234
+ do { \
1235
+ _Py_ext_module_kind kind = _get_extension_kind(def, true); \
1236
+ assert(kind == _Py_ext_module_kind_SINGLEPHASE \
1237
+ || kind == _Py_ext_module_kind_UNKNOWN); \
1238
+ } while (0)
1239
+
1240
+ #define assert_singlephase (def ) \
1241
+ assert_singlephase_def(def)
1242
+
1243
+ #else /* defined(NDEBUG) */
1244
+ #define assert_multiphase_def (def )
1245
+ #define assert_singlephase_def (def )
1246
+ #define assert_singlephase (def )
1211
1247
#endif
1212
1248
1213
1249
1214
1250
struct singlephase_global_update {
1215
1251
PyObject * m_dict ;
1252
+ PyModInitFunction m_init ;
1216
1253
};
1217
1254
1218
1255
static int
@@ -1226,10 +1263,24 @@ update_global_state_for_extension(PyThreadState *tstate,
1226
1263
assert (def -> m_base .m_copy == NULL );
1227
1264
}
1228
1265
else {
1229
- assert (def -> m_base .m_init != NULL
1230
- || is_core_module (tstate -> interp , name , path ));
1231
- if (singlephase -> m_dict == NULL ) {
1266
+ if (singlephase -> m_init != NULL ) {
1267
+ assert (singlephase -> m_dict == NULL );
1268
+ assert (def -> m_base .m_copy == NULL );
1269
+ assert (def -> m_size >= 0 );
1270
+ /* Remember pointer to module init function. */
1271
+ // XXX If two modules share a def then def->m_base will
1272
+ // reflect the last one added (here) to the global cache.
1273
+ // We should prevent this somehow. The simplest solution
1274
+ // is probably to store m_copy/m_init in the cache along
1275
+ // with the def, rather than within the def.
1276
+ def -> m_base .m_init = singlephase -> m_init ;
1277
+ }
1278
+ else if (singlephase -> m_dict == NULL ) {
1279
+ /* It must be a core builtin module. */
1280
+ assert (is_core_module (tstate -> interp , name , path ));
1281
+ assert (def -> m_size == -1 );
1232
1282
assert (def -> m_base .m_copy == NULL );
1283
+ assert (def -> m_base .m_init == NULL );
1233
1284
}
1234
1285
else {
1235
1286
assert (PyDict_Check (singlephase -> m_dict ));
@@ -1316,7 +1367,7 @@ import_find_extension(PyThreadState *tstate,
1316
1367
if (def == NULL ) {
1317
1368
return NULL ;
1318
1369
}
1319
- assert ( is_singlephase ( def ) );
1370
+ assert_singlephase ( def );
1320
1371
1321
1372
/* It may have been successfully imported previously
1322
1373
in an interpreter that allows legacy modules
@@ -1369,11 +1420,26 @@ import_find_extension(PyThreadState *tstate,
1369
1420
}
1370
1421
struct _Py_ext_module_loader_result res ;
1371
1422
if (_PyImport_RunModInitFunc (def -> m_base .m_init , info , & res ) < 0 ) {
1423
+ _Py_ext_module_loader_result_apply_error (& res , name_buf );
1372
1424
return NULL ;
1373
1425
}
1374
1426
assert (!PyErr_Occurred ());
1427
+ assert (res .err == NULL );
1428
+ assert (res .kind == _Py_ext_module_kind_SINGLEPHASE );
1375
1429
mod = res .module ;
1376
- // XXX __file__ doesn't get set!
1430
+ /* Tchnically, the init function could return a different module def.
1431
+ * Then we would probably need to update the global cache.
1432
+ * However, we don't expect anyone to change the def. */
1433
+ assert (res .def == def );
1434
+ _Py_ext_module_loader_result_clear (& res );
1435
+
1436
+ /* Remember the filename as the __file__ attribute */
1437
+ if (info -> filename != NULL ) {
1438
+ if (PyModule_AddObjectRef (mod , "__file__" , info -> filename ) < 0 ) {
1439
+ PyErr_Clear (); /* Not important enough to report */
1440
+ }
1441
+ }
1442
+
1377
1443
if (PyObject_SetItem (modules , info -> name , mod ) == -1 ) {
1378
1444
Py_DECREF (mod );
1379
1445
return NULL ;
@@ -1398,78 +1464,89 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
1398
1464
struct _Py_ext_module_loader_info * info ,
1399
1465
PyObject * spec , PyObject * modules )
1400
1466
{
1467
+ /* Core modules go through _PyImport_FixupBuiltin(). */
1468
+ assert (!is_core_module (tstate -> interp , info -> name , info -> path ));
1469
+
1401
1470
PyObject * mod = NULL ;
1402
1471
PyModuleDef * def = NULL ;
1472
+ const char * name_buf = PyBytes_AS_STRING (info -> name_encoded );
1403
1473
1404
1474
struct _Py_ext_module_loader_result res ;
1405
1475
if (_PyImport_RunModInitFunc (p0 , info , & res ) < 0 ) {
1406
1476
/* We discard res.def. */
1407
1477
assert (res .module == NULL );
1408
- assert ( PyErr_Occurred () );
1409
- goto finally ;
1478
+ _Py_ext_module_loader_result_apply_error ( & res , name_buf );
1479
+ return NULL ;
1410
1480
}
1411
1481
assert (!PyErr_Occurred ());
1482
+ assert (res .err == NULL );
1412
1483
1413
1484
mod = res .module ;
1414
1485
res .module = NULL ;
1415
1486
def = res .def ;
1416
1487
assert (def != NULL );
1417
1488
1418
- if (mod == NULL ) {
1419
- //assert(!is_singlephase( def) );
1489
+ if (res . kind == _Py_ext_module_kind_MULTIPHASE ) {
1490
+ assert_multiphase_def ( def );
1420
1491
assert (mod == NULL );
1421
1492
mod = PyModule_FromDefAndSpec (def , spec );
1422
1493
if (mod == NULL ) {
1423
- goto finally ;
1494
+ goto error ;
1424
1495
}
1425
1496
}
1426
1497
else {
1427
- assert (is_singlephase (def ));
1498
+ assert (res .kind == _Py_ext_module_kind_SINGLEPHASE );
1499
+ assert_singlephase_def (def );
1428
1500
assert (PyModule_Check (mod ));
1429
1501
1430
- const char * name_buf = PyBytes_AS_STRING (info -> name_encoded );
1431
1502
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed (name_buf ) < 0 ) {
1432
- Py_CLEAR (mod );
1433
- goto finally ;
1503
+ goto error ;
1434
1504
}
1435
1505
1436
- /* Remember pointer to module init function. */
1437
- def -> m_base .m_init = p0 ;
1438
-
1506
+ /* Remember the filename as the __file__ attribute */
1439
1507
if (info -> filename != NULL ) {
1440
- /* Remember the filename as the __file__ attribute */
1441
1508
if (PyModule_AddObjectRef (mod , "__file__" , info -> filename ) < 0 ) {
1442
1509
PyErr_Clear (); /* Not important enough to report */
1443
1510
}
1444
1511
}
1445
1512
1513
+ /* Update global import state. */
1446
1514
struct singlephase_global_update singlephase = {0 };
1447
1515
// gh-88216: Extensions and def->m_base.m_copy can be updated
1448
1516
// when the extension module doesn't support sub-interpreters.
1449
- if (def -> m_size == -1
1450
- && ! is_core_module ( tstate -> interp , info -> name , info -> path ))
1451
- {
1517
+ if (def -> m_size == -1 ) {
1518
+ /* We will reload from m_copy. */
1519
+ assert ( def -> m_base . m_init == NULL );
1452
1520
singlephase .m_dict = PyModule_GetDict (mod );
1453
1521
assert (singlephase .m_dict != NULL );
1454
1522
}
1523
+ else {
1524
+ /* We will reload via the init function. */
1525
+ assert (def -> m_size >= 0 );
1526
+ singlephase .m_init = p0 ;
1527
+ }
1455
1528
if (update_global_state_for_extension (
1456
1529
tstate , info -> path , info -> name , def , & singlephase ) < 0 )
1457
1530
{
1458
- Py_CLEAR (mod );
1459
- goto finally ;
1531
+ goto error ;
1460
1532
}
1461
1533
1534
+ /* Update per-interpreter import state. */
1462
1535
PyObject * modules = get_modules_dict (tstate , true);
1463
1536
if (finish_singlephase_extension (
1464
1537
tstate , mod , def , info -> name , modules ) < 0 )
1465
1538
{
1466
- Py_CLEAR (mod );
1467
- goto finally ;
1539
+ goto error ;
1468
1540
}
1469
1541
}
1470
1542
1471
- finally :
1543
+ _Py_ext_module_loader_result_clear ( & res );
1472
1544
return mod ;
1545
+
1546
+ error :
1547
+ Py_XDECREF (mod );
1548
+ _Py_ext_module_loader_result_clear (& res );
1549
+ return NULL ;
1473
1550
}
1474
1551
1475
1552
@@ -1532,7 +1609,7 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
1532
1609
* module state, but we also don't populate def->m_base.m_copy
1533
1610
* for them. */
1534
1611
assert (is_core_module (tstate -> interp , nameobj , nameobj ));
1535
- assert ( is_singlephase ( def ) );
1612
+ assert_singlephase_def ( def );
1536
1613
assert (def -> m_size == -1 );
1537
1614
assert (def -> m_base .m_copy == NULL );
1538
1615
@@ -1586,7 +1663,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
1586
1663
PyObject * mod = import_find_extension (tstate , & info );
1587
1664
if (mod != NULL ) {
1588
1665
assert (!_PyErr_Occurred (tstate ));
1589
- assert ( is_singlephase ( _PyModule_GetDef (mod ) ));
1666
+ assert_singlephase ( _PyModule_GetDef (mod ));
1590
1667
goto finally ;
1591
1668
}
1592
1669
else if (_PyErr_Occurred (tstate )) {
@@ -3940,7 +4017,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file)
3940
4017
mod = import_find_extension (tstate , & info );
3941
4018
if (mod != NULL ) {
3942
4019
assert (!_PyErr_Occurred (tstate ));
3943
- assert ( is_singlephase ( _PyModule_GetDef (mod ) ));
4020
+ assert_singlephase ( _PyModule_GetDef (mod ));
3944
4021
goto finally ;
3945
4022
}
3946
4023
else if (_PyErr_Occurred (tstate )) {
0 commit comments