Skip to content

Commit

Permalink
bpo-39778: Don't traverse weak-reference lists OrderedDict's tp_trave…
Browse files Browse the repository at this point in the history
…rse and tp_clear (GH-18749)

Objects do not own weak references to them directly through the __weakref__ list so these
do not need to be traversed by the GC.
  • Loading branch information
pablogsal committed Mar 2, 2020
1 parent b3b9ade commit 0c2b509
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 2 deletions.
20 changes: 20 additions & 0 deletions Lib/test/test_ordered_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,26 @@ def test_iterators_pickling(self):
self.assertEqual(list(unpickled), expected)
self.assertEqual(list(it), expected)

@support.cpython_only
def test_weakref_list_is_not_traversed(self):
# Check that the weakref list is not traversed when collecting
# OrderedDict objects. See bpo-39778 for more information.

gc.collect()

x = self.OrderedDict()
x.cycle = x

cycle = []
cycle.append(cycle)

x_ref = weakref.ref(x)
cycle.append(x_ref)

del x, cycle, x_ref

gc.collect()


class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed a crash due to incorrect handling of weak references in
``collections.OrderedDict`` classes. Patch by Pablo Galindo.
2 changes: 0 additions & 2 deletions Objects/odictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,6 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
_ODictNode *node;

Py_VISIT(od->od_inst_dict);
Py_VISIT(od->od_weakreflist);
_odict_FOREACH(od, node) {
Py_VISIT(_odictnode_KEY(node));
}
Expand All @@ -1467,7 +1466,6 @@ static int
odict_tp_clear(PyODictObject *od)
{
Py_CLEAR(od->od_inst_dict);
Py_CLEAR(od->od_weakreflist);
PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od);
return 0;
Expand Down

0 comments on commit 0c2b509

Please sign in to comment.