@@ -1088,7 +1088,7 @@ set_version_unlocked(PyTypeObject *tp, unsigned int version)
10881088}
10891089
10901090static void
1091- type_modified_unlocked (PyTypeObject * type )
1091+ type_modified_unlocked (PyTypeObject * type , bool world_stopped )
10921092{
10931093 /* Invalidate any cached data for the specified type and all
10941094 subclasses. This function is called after the base
@@ -1105,6 +1105,15 @@ type_modified_unlocked(PyTypeObject *type)
11051105 We don't assign new version tags eagerly, but only as
11061106 needed.
11071107 */
1108+ #ifdef Py_DEBUG
1109+ if (world_stopped ) {
1110+ assert (types_world_is_stopped ());
1111+ } else {
1112+ if (TYPE_IS_REVEALED (type )) {
1113+ ASSERT_TYPE_LOCK_HELD ();
1114+ }
1115+ }
1116+ #endif
11081117 if (type -> tp_version_tag == 0 ) {
11091118 return ;
11101119 }
@@ -1122,7 +1131,7 @@ type_modified_unlocked(PyTypeObject *type)
11221131 if (subclass == NULL ) {
11231132 continue ;
11241133 }
1125- type_modified_unlocked (subclass );
1134+ type_modified_unlocked (subclass , world_stopped );
11261135 Py_DECREF (subclass );
11271136 }
11281137 }
@@ -1139,6 +1148,9 @@ type_modified_unlocked(PyTypeObject *type)
11391148 if (type -> tp_watched ) {
11401149 // Note that PyErr_FormatUnraisable is re-entrant and the watcher
11411150 // callback might be too.
1151+ if (world_stopped ) {
1152+ types_start_world ();
1153+ }
11421154 PyInterpreterState * interp = _PyInterpreterState_GET ();
11431155 int bits = type -> tp_watched ;
11441156 int i = 0 ;
@@ -1155,6 +1167,9 @@ type_modified_unlocked(PyTypeObject *type)
11551167 i ++ ;
11561168 bits >>= 1 ;
11571169 }
1170+ if (world_stopped ) {
1171+ types_stop_world ();
1172+ }
11581173 }
11591174}
11601175
@@ -1167,7 +1182,7 @@ PyType_Modified(PyTypeObject *type)
11671182 }
11681183
11691184 BEGIN_TYPE_LOCK ();
1170- type_modified_unlocked (type );
1185+ type_modified_unlocked (type , false );
11711186 END_TYPE_LOCK ();
11721187}
11731188
@@ -1195,7 +1210,7 @@ has_custom_mro(PyTypeObject *tp)
11951210}
11961211
11971212static void
1198- type_mro_modified (PyTypeObject * type , PyObject * bases , bool is_new_type )
1213+ type_mro_modified (PyTypeObject * type , PyObject * bases , bool world_stopped )
11991214{
12001215 ASSERT_NEW_OR_STOPPED (type );
12011216 /*
@@ -1212,12 +1227,12 @@ type_mro_modified(PyTypeObject *type, PyObject *bases, bool is_new_type)
12121227 */
12131228 if (!Py_IS_TYPE (type , & PyType_Type )) {
12141229 unsigned int meta_version = Py_TYPE (type )-> tp_version_tag ;
1215- if (! is_new_type ) {
1230+ if (world_stopped ) {
12161231 types_start_world ();
12171232 }
12181233 // This can be re-entrant.
12191234 bool is_custom = has_custom_mro (type );
1220- if (! is_new_type ) {
1235+ if (world_stopped ) {
12211236 types_stop_world ();
12221237 }
12231238 if (meta_version != Py_TYPE (type )-> tp_version_tag ) {
@@ -1621,7 +1636,7 @@ type_set_abstractmethods(PyObject *tp, PyObject *value, void *Py_UNUSED(closure)
16211636 }
16221637
16231638 types_stop_world ();
1624- type_modified_unlocked (type );
1639+ type_modified_unlocked (type , true );
16251640 if (abstract )
16261641 type_set_flags_with_mask (type , 0 , Py_TPFLAGS_IS_ABSTRACT );
16271642 else
@@ -1675,17 +1690,17 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
16751690 update_callback callback , void * data );
16761691
16771692static int
1678- mro_hierarchy (PyTypeObject * type , PyObject * temp , bool is_new_type )
1693+ mro_hierarchy (PyTypeObject * type , PyObject * temp , bool world_stopped )
16791694{
16801695#ifdef Py_DEBUG
1681- if (is_new_type ) {
1696+ if (! world_stopped ) {
16821697 assert (!TYPE_IS_REVEALED (type ));
16831698 } else {
16841699 assert (types_world_is_stopped ());
16851700 }
16861701#endif
16871702 PyObject * old_mro ;
1688- int res = mro_internal (type , 0 , & old_mro , is_new_type );
1703+ int res = mro_internal (type , 0 , & old_mro , world_stopped );
16891704 if (res <= 0 ) {
16901705 /* error / reentrance */
16911706 return res ;
@@ -1735,7 +1750,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp, bool is_new_type)
17351750 Py_ssize_t n = PyList_GET_SIZE (subclasses );
17361751 for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
17371752 PyTypeObject * subclass = _PyType_CAST (PyList_GET_ITEM (subclasses , i ));
1738- res = mro_hierarchy (subclass , temp , is_new_type );
1753+ res = mro_hierarchy (subclass , temp , world_stopped );
17391754 if (res < 0 ) {
17401755 break ;
17411756 }
@@ -1826,7 +1841,7 @@ type_set_bases_world_stopped(PyTypeObject *type, PyObject *new_bases, PyTypeObje
18261841 if (temp == NULL ) {
18271842 goto bail ;
18281843 }
1829- if (mro_hierarchy (type , temp , false ) < 0 ) {
1844+ if (mro_hierarchy (type , temp , true ) < 0 ) {
18301845 goto undo ;
18311846 }
18321847 Py_DECREF (temp );
@@ -3464,7 +3479,7 @@ mro_check(PyTypeObject *type, PyObject *mro)
34643479 - through a finalizer of the return value of mro().
34653480*/
34663481static PyObject *
3467- mro_invoke (PyTypeObject * type , bool is_new_type )
3482+ mro_invoke (PyTypeObject * type , bool world_stopped )
34683483{
34693484 PyObject * mro_result ;
34703485 PyObject * new_mro ;
@@ -3474,7 +3489,7 @@ mro_invoke(PyTypeObject *type, bool is_new_type)
34743489 if (custom ) {
34753490 // Custom mro() method on metaclass. This is potentially re-entrant.
34763491 // We are called either from type_ready() or from type_set_bases().
3477- if (! is_new_type ) {
3492+ if (world_stopped ) {
34783493 // Called for type_set_bases(), re-assigment of __bases__
34793494 types_start_world ();
34803495 }
@@ -3486,7 +3501,7 @@ mro_invoke(PyTypeObject *type, bool is_new_type)
34863501 else {
34873502 new_mro = NULL ;
34883503 }
3489- if (! is_new_type ) {
3504+ if (world_stopped ) {
34903505 types_stop_world ();
34913506 }
34923507 }
@@ -3542,10 +3557,10 @@ mro_invoke(PyTypeObject *type, bool is_new_type)
35423557 - Returns -1 in case of an error.
35433558*/
35443559static int
3545- mro_internal (PyTypeObject * type , int initial , PyObject * * p_old_mro , bool is_new_type )
3560+ mro_internal (PyTypeObject * type , int initial , PyObject * * p_old_mro , bool world_stopped )
35463561{
35473562#ifdef Py_DEBUG
3548- if (is_new_type ) {
3563+ if (! world_stopped ) {
35493564 assert (!TYPE_IS_REVEALED (type ));
35503565 } else {
35513566 assert (types_world_is_stopped ());
@@ -3559,7 +3574,7 @@ mro_internal(PyTypeObject *type, int initial, PyObject **p_old_mro, bool is_new_
35593574 Don't let old_mro be GC'ed and its address be reused for
35603575 another object, like (suddenly!) a new tp_mro. */
35613576 old_mro = Py_XNewRef (lookup_tp_mro (type ));
3562- new_mro = mro_invoke (type , is_new_type ); /* might cause reentrance */
3577+ new_mro = mro_invoke (type , world_stopped ); /* might cause reentrance */
35633578 reent = (lookup_tp_mro (type ) != old_mro );
35643579 Py_XDECREF (old_mro );
35653580 if (new_mro == NULL ) {
@@ -3573,14 +3588,14 @@ mro_internal(PyTypeObject *type, int initial, PyObject **p_old_mro, bool is_new_
35733588
35743589 set_tp_mro (type , new_mro , initial );
35753590
3576- type_mro_modified (type , new_mro , is_new_type );
3591+ type_mro_modified (type , new_mro , world_stopped );
35773592 /* corner case: the super class might have been hidden
35783593 from the custom MRO */
3579- type_mro_modified (type , lookup_tp_bases (type ), is_new_type );
3594+ type_mro_modified (type , lookup_tp_bases (type ), world_stopped );
35803595
35813596 // XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE?
35823597 if (!(type -> tp_flags & _Py_TPFLAGS_STATIC_BUILTIN )) {
3583- type_modified_unlocked (type );
3598+ type_modified_unlocked (type , world_stopped );
35843599 }
35853600 else {
35863601 /* For static builtin types, this is only called during init
@@ -6162,7 +6177,7 @@ _Py_type_getattro(PyObject *tp, PyObject *name)
61626177// the type versions.
61636178static int
61646179type_update_dict (PyTypeObject * type , PyDictObject * dict , PyObject * name ,
6165- PyObject * value , PyObject * * old_value )
6180+ PyObject * value , PyObject * * old_value , bool world_stopped )
61666181{
61676182 // We don't want any re-entrancy between when we update the dict
61686183 // and call type_modified_unlocked, including running the destructor
@@ -6174,20 +6189,20 @@ type_update_dict(PyTypeObject *type, PyDictObject *dict, PyObject *name,
61746189 return -1 ;
61756190 }
61766191
6177- /* Clear the VALID_VERSION flag of 'type' and all its
6178- subclasses. This could possibly be unified with the
6179- update_subclasses() recursion in update_slot(), but carefully:
6180- they each have their own conditions on which to stop
6181- recursing into subclasses. */
6182- type_modified_unlocked (type );
6183-
61846192 if (_PyDict_SetItem_LockHeld (dict , name , value ) < 0 ) {
61856193 PyErr_Format (PyExc_AttributeError ,
61866194 "type object '%.50s' has no attribute '%U'" ,
61876195 ((PyTypeObject * )type )-> tp_name , name );
61886196 return -2 ;
61896197 }
61906198
6199+ /* Clear the VALID_VERSION flag of 'type' and all its
6200+ subclasses. This could possibly be unified with the
6201+ update_subclasses() recursion in update_slot(), but carefully:
6202+ they each have their own conditions on which to stop
6203+ recursing into subclasses. */
6204+ type_modified_unlocked (type , world_stopped );
6205+
61916206 return 0 ;
61926207}
61936208
@@ -6267,7 +6282,8 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
62676282 // that the dict object mutex is held. So, we acquire it here to
62686283 // avoid those assert failing.
62696284 Py_BEGIN_CRITICAL_SECTION (dict );
6270- res = type_update_dict (type , (PyDictObject * )dict , name , value , & old_value );
6285+ res = type_update_dict (type , (PyDictObject * )dict , name , value ,
6286+ & old_value , true);
62716287 if (res == 0 ) {
62726288 res = update_slot (type , name );
62736289 }
@@ -6276,7 +6292,8 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
62766292 } else {
62776293 // The name is not a slot.
62786294 BEGIN_TYPE_DICT_LOCK (dict );
6279- res = type_update_dict (type , (PyDictObject * )dict , name , value , & old_value );
6295+ res = type_update_dict (type , (PyDictObject * )dict , name , value ,
6296+ & old_value , false);
62806297 END_TYPE_DICT_LOCK ();
62816298 }
62826299 if (res == -2 ) {
@@ -8625,7 +8642,7 @@ type_ready_mro(PyTypeObject *type, int initial)
86258642 }
86268643
86278644 /* Calculate method resolution order */
8628- if (mro_internal (type , initial , NULL , true ) < 0 ) {
8645+ if (mro_internal (type , initial , NULL , false ) < 0 ) {
86298646 return -1 ;
86308647 }
86318648 PyObject * mro = lookup_tp_mro (type );
@@ -11434,15 +11451,15 @@ update_all_slots(PyTypeObject* type)
1143411451{
1143511452 pytype_slotdef * p ;
1143611453
11437- ASSERT_NEW_OR_STOPPED (type );
11438-
11439- /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
11440- type_modified_unlocked (type );
11454+ assert (types_world_is_stopped ());
1144111455
1144211456 for (p = slotdefs ; p -> name ; p ++ ) {
1144311457 /* update_slot returns int but can't actually fail */
1144411458 update_slot (type , p -> name_strobj );
1144511459 }
11460+
11461+ /* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
11462+ type_modified_unlocked (type , true);
1144611463}
1144711464
1144811465
@@ -11715,7 +11732,7 @@ PyType_Freeze(PyTypeObject *type)
1171511732
1171611733 types_stop_world ();
1171711734 type_add_flags (type , Py_TPFLAGS_IMMUTABLETYPE );
11718- type_modified_unlocked (type );
11735+ type_modified_unlocked (type , true );
1171911736 types_start_world ();
1172011737
1172111738 return 0 ;
0 commit comments