From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Mon, 2 Mar 2020 23:53:03 +0000 (-0800) Subject: bpo-39778: Don't traverse weak-reference lists OrderedDict's tp_traverse and tp_clear... X-Git-Tag: v3.7.7rc1~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=69ded3944c202da972754644c0bbf7f77cc5e8ea;p=thirdparty%2FPython%2Fcpython.git 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 0c2b509f9d1d3a9065bc62c2407e1dc2ed70e9c2) Co-authored-by: Pablo Galindo --- diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index b1d7f86a6760..0e5c7fc75038 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -749,6 +749,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): diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-03-02-19-21-21.bpo-39778._YGLEc.rst b/Misc/NEWS.d/next/Core and Builtins/2020-03-02-19-21-21.bpo-39778._YGLEc.rst new file mode 100644 index 000000000000..dc4951216736 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-03-02-19-21-21.bpo-39778._YGLEc.rst @@ -0,0 +1,2 @@ +Fixed a crash due to incorrect handling of weak references in +``collections.OrderedDict`` classes. Patch by Pablo Galindo. diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 88afc61f6071..c1fee04c4227 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1463,7 +1463,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)); } @@ -1476,7 +1475,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;