diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -438,6 +438,7 @@ static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static void remove_subclass(PyTypeObject *, PyTypeObject *); +static void remove_all_subclasses(PyTypeObject *type); static void update_all_slots(PyTypeObject *); typedef int (*update_callback)(PyTypeObject *, void *); @@ -2713,6 +2714,7 @@ et = (PyHeapTypeObject *)type; Py_XDECREF(type->tp_base); Py_XDECREF(type->tp_dict); + remove_all_subclasses(type); Py_XDECREF(type->tp_bases); Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); @@ -4317,9 +4319,8 @@ static int add_subclass(PyTypeObject *base, PyTypeObject *type) { - Py_ssize_t i; int result; - PyObject *list, *ref, *newobj; + PyObject *list, *newobj; list = base->tp_subclasses; if (list == NULL) { @@ -4329,13 +4330,6 @@ } assert(PyList_Check(list)); newobj = PyWeakref_NewRef((PyObject *)type, NULL); - i = PyList_GET_SIZE(list); - while (--i >= 0) { - ref = PyList_GET_ITEM(list, i); - assert(PyWeakref_CheckRef(ref)); - if (PyWeakref_GET_OBJECT(ref) == Py_None) - return PyList_SetItem(list, i, newobj); - } result = PyList_Append(list, newobj); Py_DECREF(newobj); return result; @@ -4345,7 +4339,7 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type) { Py_ssize_t i; - PyObject *list, *ref; + PyObject *list, *ref, *target; list = base->tp_subclasses; if (list == NULL) { @@ -4356,14 +4350,36 @@ while (--i >= 0) { ref = PyList_GET_ITEM(list, i); assert(PyWeakref_CheckRef(ref)); - if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) { + target = PyWeakref_GET_OBJECT(ref); + if (target == Py_None || target == (PyObject*)type) { + /* swap the item with the last one */ + Py_ssize_t j = PyList_GET_SIZE(list)-1; + if (i != j) { + PyObject *tmp = PyList_GET_ITEM(list, j); + PyList_SET_ITEM(list, j, ref) ; + PyList_SET_ITEM(list, i, tmp); + } /* this can't fail, right? */ - PySequence_DelItem(list, i); + PySequence_DelItem(list, j); return; } } } +static void +remove_all_subclasses(PyTypeObject *type) +{ + PyObject *bases = type->tp_bases; + int i; + if (bases) { + for(i = 0; i < PyTuple_GET_SIZE(bases); i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(base)) + remove_subclass((PyTypeObject*)base, type); + } + } +} + static int check_num_args(PyObject *ob, int n) {