Skip to content

Commit 9ddcb91

Browse files
authored
[3.8] bpo-39778: Don't traverse weak-reference lists OrderedDict's tp_traverse and tp_clear (GH-18749) (GH-18756)
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)
1 parent 7ad9982 commit 9ddcb91

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
@@ -753,6 +753,26 @@ def test_iterators_pickling(self):
753753
self.assertEqual(list(unpickled), expected)
754754
self.assertEqual(list(it), expected)
755755

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

757777
class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
758778

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
@@ -1453,7 +1453,6 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
14531453
_ODictNode *node;
14541454

14551455
Py_VISIT(od->od_inst_dict);
1456-
Py_VISIT(od->od_weakreflist);
14571456
_odict_FOREACH(od, node) {
14581457
Py_VISIT(_odictnode_KEY(node));
14591458
}
@@ -1466,7 +1465,6 @@ static int
14661465
odict_tp_clear(PyODictObject *od)
14671466
{
14681467
Py_CLEAR(od->od_inst_dict);
1469-
Py_CLEAR(od->od_weakreflist);
14701468
PyDict_Clear((PyObject *)od);
14711469
_odict_clear_nodes(od);
14721470
return 0;

0 commit comments

Comments
 (0)