Skip to content

Commit 69ded39

Browse files
bpo-39778: Don't traverse weak-reference lists OrderedDict's tp_traverse 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. (cherry picked from commit 0c2b509) Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
1 parent 7ca251b commit 69ded39

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

Lib/test/test_ordered_dict.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,26 @@ def test_iterators_pickling(self):
749749
self.assertEqual(list(unpickled), expected)
750750
self.assertEqual(list(it), expected)
751751

752+
@support.cpython_only
753+
def test_weakref_list_is_not_traversed(self):
754+
# Check that the weakref list is not traversed when collecting
755+
# OrderedDict objects. See bpo-39778 for more information.
756+
757+
gc.collect()
758+
759+
x = self.OrderedDict()
760+
x.cycle = x
761+
762+
cycle = []
763+
cycle.append(cycle)
764+
765+
x_ref = weakref.ref(x)
766+
cycle.append(x_ref)
767+
768+
del x, cycle, x_ref
769+
770+
gc.collect()
771+
752772

753773
class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
754774

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a crash due to incorrect handling of weak references in
2+
``collections.OrderedDict`` classes. Patch by Pablo Galindo.

Objects/odictobject.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,6 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
14631463
_ODictNode *node;
14641464

14651465
Py_VISIT(od->od_inst_dict);
1466-
Py_VISIT(od->od_weakreflist);
14671466
_odict_FOREACH(od, node) {
14681467
Py_VISIT(_odictnode_KEY(node));
14691468
}
@@ -1476,7 +1475,6 @@ static int
14761475
odict_tp_clear(PyODictObject *od)
14771476
{
14781477
Py_CLEAR(od->od_inst_dict);
1479-
Py_CLEAR(od->od_weakreflist);
14801478
PyDict_Clear((PyObject *)od);
14811479
_odict_clear_nodes(od);
14821480
return 0;

0 commit comments

Comments
 (0)