[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)
This commit is contained in:
Pablo Galindo 2020-03-02 23:55:20 +00:00 committed by GitHub
parent 7ad99821d8
commit 9ddcb914f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 2 deletions

View File

@ -753,6 +753,26 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
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):

View File

@ -0,0 +1,2 @@
Fixed a crash due to incorrect handling of weak references in
``collections.OrderedDict`` classes. Patch by Pablo Galindo.

View File

@ -1453,7 +1453,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));
}
@ -1466,7 +1465,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;