@@ -687,27 +687,28 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
687
687
static int
688
688
mro_hierarchy (PyTypeObject * type , PyObject * temp )
689
689
{
690
- int res ;
691
- PyObject * new_mro , * old_mro ;
692
- PyObject * tuple ;
693
- PyObject * subclasses ;
694
- Py_ssize_t i , n ;
695
-
696
- res = mro_internal (type , & old_mro );
697
- if (res <= 0 )
690
+ PyObject * old_mro ;
691
+ int res = mro_internal (type , & old_mro );
692
+ if (res <= 0 ) {
698
693
/* error / reentrance */
699
694
return res ;
700
- new_mro = type -> tp_mro ;
695
+ }
696
+ PyObject * new_mro = type -> tp_mro ;
701
697
702
- if (old_mro != NULL )
698
+ PyObject * tuple ;
699
+ if (old_mro != NULL ) {
703
700
tuple = PyTuple_Pack (3 , type , new_mro , old_mro );
704
- else
701
+ }
702
+ else {
705
703
tuple = PyTuple_Pack (2 , type , new_mro );
704
+ }
706
705
707
- if (tuple != NULL )
706
+ if (tuple != NULL ) {
708
707
res = PyList_Append (temp , tuple );
709
- else
708
+ }
709
+ else {
710
710
res = -1 ;
711
+ }
711
712
Py_XDECREF (tuple );
712
713
713
714
if (res < 0 ) {
@@ -727,15 +728,18 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
727
728
Finally, this makes things simple avoiding the need to deal
728
729
with dictionary iterators and weak references.
729
730
*/
730
- subclasses = type___subclasses___impl (type );
731
- if (subclasses == NULL )
731
+ PyObject * subclasses = _PyType_GetSubclasses (type );
732
+ if (subclasses == NULL ) {
732
733
return -1 ;
733
- n = PyList_GET_SIZE (subclasses );
734
- for (i = 0 ; i < n ; i ++ ) {
734
+ }
735
+
736
+ Py_ssize_t n = PyList_GET_SIZE (subclasses );
737
+ for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
735
738
PyTypeObject * subclass = _PyType_CAST (PyList_GET_ITEM (subclasses , i ));
736
739
res = mro_hierarchy (subclass , temp );
737
- if (res < 0 )
740
+ if (res < 0 ) {
738
741
break ;
742
+ }
739
743
}
740
744
Py_DECREF (subclasses );
741
745
@@ -4124,6 +4128,42 @@ type_dealloc(PyTypeObject *type)
4124
4128
Py_TYPE (type )-> tp_free ((PyObject * )type );
4125
4129
}
4126
4130
4131
+
4132
+ PyObject *
4133
+ _PyType_GetSubclasses (PyTypeObject * self )
4134
+ {
4135
+ PyObject * list = PyList_New (0 );
4136
+ if (list == NULL ) {
4137
+ return NULL ;
4138
+ }
4139
+
4140
+ // Hold a strong reference to tp_subclasses while iterating on it
4141
+ PyObject * dict = Py_XNewRef (self -> tp_subclasses );
4142
+ if (dict == NULL ) {
4143
+ return list ;
4144
+ }
4145
+ assert (PyDict_CheckExact (dict ));
4146
+
4147
+ Py_ssize_t i = 0 ;
4148
+ PyObject * ref ; // borrowed ref
4149
+ while (PyDict_Next (dict , & i , NULL , & ref )) {
4150
+ assert (PyWeakref_CheckRef (ref ));
4151
+ PyObject * obj = PyWeakref_GET_OBJECT (ref ); // borrowed ref
4152
+ if (obj == Py_None ) {
4153
+ continue ;
4154
+ }
4155
+ assert (PyType_Check (obj ));
4156
+ if (PyList_Append (list , obj ) < 0 ) {
4157
+ Py_CLEAR (list );
4158
+ goto done ;
4159
+ }
4160
+ }
4161
+ done :
4162
+ Py_DECREF (dict );
4163
+ return list ;
4164
+ }
4165
+
4166
+
4127
4167
/*[clinic input]
4128
4168
type.__subclasses__
4129
4169
@@ -4134,28 +4174,7 @@ static PyObject *
4134
4174
type___subclasses___impl (PyTypeObject * self )
4135
4175
/*[clinic end generated code: output=eb5eb54485942819 input=5af66132436f9a7b]*/
4136
4176
{
4137
- PyObject * list , * raw , * ref ;
4138
- Py_ssize_t i ;
4139
-
4140
- list = PyList_New (0 );
4141
- if (list == NULL )
4142
- return NULL ;
4143
- raw = self -> tp_subclasses ;
4144
- if (raw == NULL )
4145
- return list ;
4146
- assert (PyDict_CheckExact (raw ));
4147
- i = 0 ;
4148
- while (PyDict_Next (raw , & i , NULL , & ref )) {
4149
- assert (PyWeakref_CheckRef (ref ));
4150
- ref = PyWeakref_GET_OBJECT (ref );
4151
- if (ref != Py_None ) {
4152
- if (PyList_Append (list , ref ) < 0 ) {
4153
- Py_DECREF (list );
4154
- return NULL ;
4155
- }
4156
- }
4157
- }
4158
- return list ;
4177
+ return _PyType_GetSubclasses (self );
4159
4178
}
4160
4179
4161
4180
static PyObject *
@@ -4165,6 +4184,7 @@ type_prepare(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
4165
4184
return PyDict_New ();
4166
4185
}
4167
4186
4187
+
4168
4188
/*
4169
4189
Merge the __dict__ of aclass into dict, and recursively also all
4170
4190
the __dict__s of aclass's base classes. The order of merging isn't
0 commit comments