@@ -580,19 +580,8 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
580
580
return ;
581
581
}
582
582
583
- Py_ssize_t i ;
584
- for (i = 0 ; i < PyList_GET_SIZE (MODULES_BY_INDEX (interp )); i ++ ) {
585
- PyObject * m = PyList_GET_ITEM (MODULES_BY_INDEX (interp ), i );
586
- if (PyModule_Check (m )) {
587
- /* cleanup the saved copy of module dicts */
588
- PyModuleDef * md = PyModule_GetDef (m );
589
- if (md ) {
590
- // XXX Do this more carefully. The dict might be owned
591
- // by another interpreter.
592
- Py_CLEAR (md -> m_base .m_copy );
593
- }
594
- }
595
- }
583
+ /* We clear out the cached module defs and copied module dicts
584
+ * in _PyImport_Fini(). */
596
585
597
586
/* Setting modules_by_index to NULL could be dangerous, so we
598
587
clear the list instead. */
@@ -652,7 +641,7 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
652
641
O. import_run_extension(): set __file__
653
642
P. import_run_extension() -> update_global_state_for_extension()
654
643
Q. update_global_state_for_extension():
655
- copy __dict__ into def->m_base.m_copy
644
+ copy __dict__ into the cached m_dict
656
645
R. update_global_state_for_extension():
657
646
add it to _PyRuntime.imports.extensions
658
647
S. import_run_extension() -> finish_singlephase_extension()
@@ -672,7 +661,7 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
672
661
F. else:
673
662
1. import_add_module() -> PyModule_NewObject()
674
663
2. import_add_module(): set it on sys.modules
675
- G. reload_singlephase_extension(): copy the "m_copy " dict into __dict__
664
+ G. reload_singlephase_extension(): copy the "m_dict " dict into __dict__
676
665
H. reload_singlephase_extension(): add to modules_by_index
677
666
678
667
(10). (every time):
@@ -854,19 +843,19 @@ We support a number of kinds of single-phase init builtin/extension modules:
854
843
855
844
* "basic"
856
845
* no module state (PyModuleDef.m_size == -1)
857
- * does not support repeated init (we use PyModuleDef.m_base.m_copy )
846
+ * does not support repeated init (we use the cached m_dict )
858
847
* may have process-global state
859
848
* the module's def is cached in _PyRuntime.imports.extensions,
860
849
by (name, filename)
861
850
* "reinit"
862
851
* no module state (PyModuleDef.m_size == 0)
863
- * supports repeated init (m_copy is never used)
852
+ * supports repeated init (m_dict is never used)
864
853
* should not have any process-global state
865
854
* its def is never cached in _PyRuntime.imports.extensions
866
855
(except, currently, under the main interpreter, for some reason)
867
856
* "with state" (almost the same as reinit)
868
857
* has module state (PyModuleDef.m_size > 0)
869
- * supports repeated init (m_copy is never used)
858
+ * supports repeated init (m_dict is never used)
870
859
* should not have any process-global state
871
860
* its def is never cached in _PyRuntime.imports.extensions
872
861
(except, currently, under the main interpreter, for some reason)
@@ -892,7 +881,7 @@ notable weirdness happens:
892
881
* (non-basic-only) its init func is used when re-loading any of them
893
882
(via the def's m_init)
894
883
* (basic-only) the copy of its __dict__ is used when re-loading any of them
895
- (via the def's m_copy )
884
+ (via the def's cached m_dict )
896
885
897
886
However, the following happens as expected:
898
887
@@ -905,7 +894,7 @@ However, the following happens as expected:
905
894
For "basic" modules there are other quirks:
906
895
907
896
* (whether sharing a def or not) when loaded the first time,
908
- m_copy is set before _init_module_attrs() is called
897
+ m_dict is set before _init_module_attrs() is called
909
898
in importlib._bootstrap.module_from_spec(),
910
899
so when the module is re-loaded, the previous value
911
900
for __wpec__ (and others) is reset, possibly unexpectedly.
@@ -948,7 +937,7 @@ typedef PyDictObject *cached_m_dict_t;
948
937
struct extensions_cache_value {
949
938
PyModuleDef * def ;
950
939
951
- /* m_init and m_copy were formerly part of PyModuleDef_Base. */
940
+ /* m_init and m_dict were formerly part of PyModuleDef_Base. */
952
941
953
942
/* The function used to re-initialize the module.
954
943
This is only set for legacy (single-phase init) extension modules
@@ -1008,7 +997,7 @@ set_cached_m_dict(struct extensions_cache_value *value, PyObject *m_dict)
1008
997
* isolated interpreter, but there are ways around that.
1009
998
* Hence, heere be dragons! Ideally we would instead do
1010
999
* something like make a read-only, immortal copy of the
1011
- * dict using PyMem_RawMalloc() and store *that* in m_copy .
1000
+ * dict using PyMem_RawMalloc() and store *that* in m_dict .
1012
1001
* Then we'd need to make sure to clear that when the
1013
1002
* runtime is finalized, rather than in
1014
1003
* PyImport_ClearModulesByIndex(). */
@@ -1051,7 +1040,7 @@ update_extensions_cache_value(struct extensions_cache_value *value,
1051
1040
/* We expect the same symbol to be used and the shared object file
1052
1041
* to have remained loaded, so it must be the same pointer. */
1053
1042
assert (value -> m_init == NULL || value -> m_init == m_init );
1054
- /* For now we don't worry about comparing value->m_copy . */
1043
+ /* For now we don't worry about comparing value->m_dict . */
1055
1044
assert (value -> m_dict == NULL || m_dict != NULL );
1056
1045
1057
1046
/* We assume that all module defs are statically allocated
@@ -1067,6 +1056,13 @@ update_extensions_cache_value(struct extensions_cache_value *value,
1067
1056
return -1 ;
1068
1057
}
1069
1058
1059
+ if (m_init != NULL ) {
1060
+ def -> m_base .m_cache_has_m_init = 1 ;
1061
+ }
1062
+ if (temp .m_dict != NULL ) {
1063
+ def -> m_base .m_cache_has_m_dict = 1 ;
1064
+ }
1065
+
1070
1066
* value = temp ;
1071
1067
return 0 ;
1072
1068
}
@@ -1396,7 +1392,7 @@ _get_extension_kind(PyModuleDef *def, bool check_size)
1396
1392
enum _Py_ext_module_kind kind ;
1397
1393
if (def == NULL ) {
1398
1394
/* It must be a module created by reload_singlephase_extension()
1399
- * from m_copy . Ideally we'd do away with this case. */
1395
+ * from m_dict . Ideally we'd do away with this case. */
1400
1396
kind = _Py_ext_module_kind_SINGLEPHASE ;
1401
1397
}
1402
1398
else if (def -> m_slots != NULL ) {
@@ -1405,7 +1401,10 @@ _get_extension_kind(PyModuleDef *def, bool check_size)
1405
1401
else if (check_size && def -> m_size == -1 ) {
1406
1402
kind = _Py_ext_module_kind_SINGLEPHASE ;
1407
1403
}
1408
- else if (def -> m_base .m_init != NULL ) {
1404
+ else if (def -> m_base .m_cache_has_m_init ) {
1405
+ kind = _Py_ext_module_kind_SINGLEPHASE ;
1406
+ }
1407
+ else if (def -> m_base .m_cache_has_m_dict ) {
1409
1408
kind = _Py_ext_module_kind_SINGLEPHASE ;
1410
1409
}
1411
1410
else {
@@ -1451,8 +1450,9 @@ update_global_state_for_extension(PyThreadState *tstate,
1451
1450
PyModInitFunction m_init = NULL ;
1452
1451
PyObject * m_dict = NULL ;
1453
1452
1454
- assert (def -> m_base .m_init == NULL );
1455
- assert (def -> m_base .m_copy == NULL );
1453
+ /* It shouldn't have been set yet. */
1454
+ assert (!def -> m_base .m_cache_has_m_init );
1455
+ assert (!def -> m_base .m_cache_has_m_dict );
1456
1456
1457
1457
/* Set up for _extensions_cache_set(). */
1458
1458
if (singlephase != NULL ) {
@@ -1473,7 +1473,7 @@ update_global_state_for_extension(PyThreadState *tstate,
1473
1473
else {
1474
1474
assert (singlephase -> m_dict != NULL
1475
1475
&& PyDict_Check (singlephase -> m_dict ));
1476
- // gh-88216: Extensions and def->m_base.m_copy can be updated
1476
+ // gh-88216: Extensions and the cached m_dict can be updated
1477
1477
// when the extension module doesn't support sub-interpreters.
1478
1478
assert (def -> m_size == -1 );
1479
1479
assert (!is_core_module (tstate -> interp , name , path ));
@@ -1496,6 +1496,8 @@ update_global_state_for_extension(PyThreadState *tstate,
1496
1496
// mark the module as not loadable.
1497
1497
return -1 ;
1498
1498
}
1499
+ assert (def -> m_base .m_cache_has_m_init
1500
+ || def -> m_base .m_cache_has_m_dict );
1499
1501
}
1500
1502
1501
1503
return 0 ;
@@ -1547,14 +1549,15 @@ reload_singlephase_extension(PyThreadState *tstate,
1547
1549
if (def -> m_size == -1 ) {
1548
1550
/* Module does not support repeated initialization */
1549
1551
assert (cached -> m_init == NULL );
1550
- assert (def -> m_base .m_init == NULL );
1552
+ assert (!def -> m_base .m_cache_has_m_init );
1553
+ assert (def -> m_base .m_cache_has_m_dict );
1551
1554
// XXX Copying the cached dict may break interpreter isolation.
1552
1555
// We could solve this by temporarily acquiring the original
1553
1556
// interpreter's GIL.
1554
1557
PyObject * m_copy = get_cached_m_dict (cached );
1555
1558
if (m_copy == NULL ) {
1556
1559
/* It might be a core module (e.g. sys & builtins),
1557
- for which we don't set m_copy . */
1560
+ for which we don't cache m_dict . */
1558
1561
m_copy = get_core_module_dict (
1559
1562
tstate -> interp , info -> name , info -> path );
1560
1563
if (m_copy == NULL ) {
@@ -1589,7 +1592,8 @@ reload_singlephase_extension(PyThreadState *tstate,
1589
1592
}
1590
1593
else {
1591
1594
assert (cached -> m_dict == NULL );
1592
- assert (def -> m_base .m_copy == NULL );
1595
+ assert (def -> m_base .m_cache_has_m_init );
1596
+ assert (!def -> m_base .m_cache_has_m_dict );
1593
1597
PyModInitFunction p0 = cached -> m_init ;
1594
1598
if (p0 == NULL ) {
1595
1599
assert (!PyErr_Occurred ());
@@ -1714,18 +1718,16 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
1714
1718
1715
1719
/* Update global import state. */
1716
1720
struct singlephase_global_update singlephase = {0 };
1717
- // gh-88216: Extensions and def->m_base.m_copy can be updated
1721
+ // gh-88216: Extensions and def->m_base.m_dict can be updated
1718
1722
// when the extension module doesn't support sub-interpreters.
1719
1723
if (def -> m_size == -1 ) {
1720
- /* We will reload from m_copy. */
1721
- assert (def -> m_base .m_init == NULL );
1724
+ /* We will reload from m_dict. */
1722
1725
singlephase .m_dict = PyModule_GetDict (mod );
1723
1726
assert (singlephase .m_dict != NULL );
1724
1727
}
1725
1728
else {
1726
1729
/* We will reload via the init function. */
1727
1730
assert (def -> m_size >= 0 );
1728
- assert (def -> m_base .m_copy == NULL );
1729
1731
singlephase .m_init = p0 ;
1730
1732
}
1731
1733
if (update_global_state_for_extension (
@@ -1765,8 +1767,8 @@ clear_singlephase_extension(PyInterpreterState *interp,
1765
1767
PyModuleDef * def = value -> def ;
1766
1768
1767
1769
/* Clear data set when the module was initially loaded. */
1768
- def -> m_base .m_init = NULL ;
1769
- Py_CLEAR ( def -> m_base .m_copy ) ;
1770
+ def -> m_base .m_cache_has_m_init = 0 ;
1771
+ def -> m_base .m_cache_has_m_dict = 0 ;
1770
1772
// We leave m_index alone since there's no reason to reset it.
1771
1773
1772
1774
/* Clear the PyState_*Module() cache entry. */
@@ -1808,22 +1810,23 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
1808
1810
1809
1811
/* We only use _PyImport_FixupBuiltin() for the core builtin modules
1810
1812
* (sys and builtins). These modules are single-phase init with no
1811
- * module state, but we also don't populate def->m_base.m_copy
1813
+ * module state, but we also don't populate the cached m_dict
1812
1814
* for them. */
1813
1815
assert (is_core_module (tstate -> interp , nameobj , nameobj ));
1814
1816
assert (check_singlephase (def ));
1815
1817
assert (def -> m_size == -1 );
1816
- assert (def -> m_base .m_copy == NULL );
1817
1818
1818
1819
struct singlephase_global_update singlephase = {
1819
- /* We don't want def->m_base.m_copy populated. */
1820
+ /* We don't want the cached m_dict populated. */
1820
1821
.m_dict = NULL ,
1821
1822
};
1822
1823
if (update_global_state_for_extension (
1823
1824
tstate , nameobj , nameobj , def , & singlephase ) < 0 )
1824
1825
{
1825
1826
goto finally ;
1826
1827
}
1828
+ assert (!def -> m_base .m_cache_has_m_init );
1829
+ assert (def -> m_base .m_cache_has_m_dict );
1827
1830
1828
1831
if (finish_singlephase_extension (tstate , mod , def , nameobj , modules ) < 0 ) {
1829
1832
goto finally ;
0 commit comments