Issue #25395: Fixed crash when highly nested OrderedDict structures were
garbage collected.
This commit is contained in:
parent
964ec8b2f3
commit
14eefe353e
|
@ -2025,6 +2025,30 @@ class OrderedDictTests:
|
|||
items = [('a', 1), ('c', 3), ('b', 2)]
|
||||
self.assertEqual(list(MyOD(items).items()), items)
|
||||
|
||||
def test_highly_nested(self):
|
||||
# Issue 25395: crashes during garbage collection
|
||||
OrderedDict = self.module.OrderedDict
|
||||
obj = None
|
||||
for _ in range(1000):
|
||||
obj = OrderedDict([(None, obj)])
|
||||
del obj
|
||||
support.gc_collect()
|
||||
|
||||
def test_highly_nested_subclass(self):
|
||||
# Issue 25395: crashes during garbage collection
|
||||
OrderedDict = self.module.OrderedDict
|
||||
deleted = []
|
||||
class MyOD(OrderedDict):
|
||||
def __del__(self):
|
||||
deleted.append(self.i)
|
||||
obj = None
|
||||
for i in range(100):
|
||||
obj = MyOD([(None, obj)])
|
||||
obj.i = i
|
||||
del obj
|
||||
support.gc_collect()
|
||||
self.assertEqual(deleted, list(reversed(range(100))))
|
||||
|
||||
|
||||
class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ Release date: TBA
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #25395: Fixed crash when highly nested OrderedDict structures were
|
||||
garbage collected.
|
||||
|
||||
- Issue #25274: sys.setrecursionlimit() now raises a RecursionError if the new
|
||||
recursion limit is too low depending at the current recursion depth. Modify
|
||||
also the "lower-water mark" formula to make it monotonic. This mark is used
|
||||
|
|
|
@ -1431,17 +1431,28 @@ static PyMemberDef odict_members[] = {
|
|||
static void
|
||||
odict_dealloc(PyODictObject *self)
|
||||
{
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_SAFE_BEGIN(self);
|
||||
Py_TRASHCAN_SAFE_BEGIN(self)
|
||||
|
||||
Py_XDECREF(self->od_inst_dict);
|
||||
if (self->od_weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *)self);
|
||||
|
||||
_odict_clear_nodes(self);
|
||||
Py_TRASHCAN_SAFE_END(self);
|
||||
|
||||
/* must be last */
|
||||
/* Call the base tp_dealloc(). Since it too uses the trashcan mechanism,
|
||||
* temporarily decrement trash_delete_nesting to prevent triggering it
|
||||
* and putting the partially deallocated object on the trashcan's
|
||||
* to-be-deleted-later list.
|
||||
*/
|
||||
--tstate->trash_delete_nesting;
|
||||
assert(_tstate->trash_delete_nesting < PyTrash_UNWIND_LEVEL);
|
||||
PyDict_Type.tp_dealloc((PyObject *)self);
|
||||
++tstate->trash_delete_nesting;
|
||||
|
||||
Py_TRASHCAN_SAFE_END(self)
|
||||
};
|
||||
|
||||
/* tp_repr */
|
||||
|
|
Loading…
Reference in New Issue