Issue #25395: Fixed crash when highly nested OrderedDict structures were

garbage collected.
This commit is contained in:
Serhiy Storchaka 2015-11-01 16:12:34 +02:00
parent 964ec8b2f3
commit 14eefe353e
3 changed files with 41 additions and 3 deletions

View File

@ -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):

View File

@ -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

View File

@ -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 */