]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-39778: Don't traverse weak-reference lists OrderedDict's tp_traverse and tp_clear...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 2 Mar 2020 23:53:03 +0000 (15:53 -0800)
committerGitHub <noreply@github.com>
Mon, 2 Mar 2020 23:53:03 +0000 (15:53 -0800)
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 <Pablogsal@gmail.com>
Lib/test/test_ordered_dict.py
Misc/NEWS.d/next/Core and Builtins/2020-03-02-19-21-21.bpo-39778._YGLEc.rst [new file with mode: 0644]
Objects/odictobject.c

index b1d7f86a6760b3b4016edf0bd05d49545afe26cf..0e5c7fc7503895888ac1508c5174d807f5c2ef7a 100644 (file)
@@ -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 (file)
index 0000000..dc49512
--- /dev/null
@@ -0,0 +1,2 @@
+Fixed a crash due to incorrect handling of weak references in
+``collections.OrderedDict`` classes. Patch by Pablo Galindo.
index 88afc61f6071da89ec3095b2030d80fa9751d6e9..c1fee04c4227db2cad969ad32fc68f22bcf8dca3 100644 (file)
@@ -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;