@@ -687,27 +687,28 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
687687static int
688688mro_hierarchy (PyTypeObject * type , PyObject * temp )
689689{
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 ) {
698693 /* error / reentrance */
699694 return res ;
700- new_mro = type -> tp_mro ;
695+ }
696+ PyObject * new_mro = type -> tp_mro ;
701697
702- if (old_mro != NULL )
698+ PyObject * tuple ;
699+ if (old_mro != NULL ) {
703700 tuple = PyTuple_Pack (3 , type , new_mro , old_mro );
704- else
701+ }
702+ else {
705703 tuple = PyTuple_Pack (2 , type , new_mro );
704+ }
706705
707- if (tuple != NULL )
706+ if (tuple != NULL ) {
708707 res = PyList_Append (temp , tuple );
709- else
708+ }
709+ else {
710710 res = -1 ;
711+ }
711712 Py_XDECREF (tuple );
712713
713714 if (res < 0 ) {
@@ -727,15 +728,18 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
727728 Finally, this makes things simple avoiding the need to deal
728729 with dictionary iterators and weak references.
729730 */
730- subclasses = type___subclasses___impl (type );
731- if (subclasses == NULL )
731+ PyObject * subclasses = _PyType_GetSubclasses (type );
732+ if (subclasses == NULL ) {
732733 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 ++ ) {
735738 PyTypeObject * subclass = _PyType_CAST (PyList_GET_ITEM (subclasses , i ));
736739 res = mro_hierarchy (subclass , temp );
737- if (res < 0 )
740+ if (res < 0 ) {
738741 break ;
742+ }
739743 }
740744 Py_DECREF (subclasses );
741745
@@ -4124,6 +4128,42 @@ type_dealloc(PyTypeObject *type)
41244128 Py_TYPE (type )-> tp_free ((PyObject * )type );
41254129}
41264130
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+
41274167/*[clinic input]
41284168type.__subclasses__
41294169
@@ -4134,28 +4174,7 @@ static PyObject *
41344174type___subclasses___impl (PyTypeObject * self )
41354175/*[clinic end generated code: output=eb5eb54485942819 input=5af66132436f9a7b]*/
41364176{
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 );
41594178}
41604179
41614180static PyObject *
@@ -4165,6 +4184,7 @@ type_prepare(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
41654184 return PyDict_New ();
41664185}
41674186
4187+
41684188/*
41694189 Merge the __dict__ of aclass into dict, and recursively also all
41704190 the __dict__s of aclass's base classes. The order of merging isn't
0 commit comments