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.
This commit is contained in:
Pablo Galindo 2020-03-02 23:12:54 +00:00 committed by GitHub
parent b3b9ade4a3
commit 0c2b509f9d
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(unpickled), expected)
self.assertEqual(list(it), 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): 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

@ -1454,7 +1454,6 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
_ODictNode *node; _ODictNode *node;
Py_VISIT(od->od_inst_dict); Py_VISIT(od->od_inst_dict);
Py_VISIT(od->od_weakreflist);
_odict_FOREACH(od, node) { _odict_FOREACH(od, node) {
Py_VISIT(_odictnode_KEY(node)); Py_VISIT(_odictnode_KEY(node));
} }
@ -1467,7 +1466,6 @@ static int
odict_tp_clear(PyODictObject *od) odict_tp_clear(PyODictObject *od)
{ {
Py_CLEAR(od->od_inst_dict); Py_CLEAR(od->od_inst_dict);
Py_CLEAR(od->od_weakreflist);
PyDict_Clear((PyObject *)od); PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od); _odict_clear_nodes(od);
return 0; return 0;