Commit 4918b47c authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #25935: Garbage collector now breaks reference loops with OrderedDict.

parents 31a858cb d205d014
import contextlib
import copy
import gc
import pickle
from random import randrange, shuffle
import struct
import sys
import unittest
import weakref
from collections.abc import MutableMapping
from test import mapping_tests, support
......@@ -593,6 +595,17 @@ class OrderedDictTests:
dict.update(od, [('spam', 1)])
self.assertNotIn('NULL', repr(od))
def test_reference_loop(self):
# Issue 25935
OrderedDict = self.OrderedDict
class A:
od = OrderedDict()
A.od[A] = None
r = weakref.ref(A)
del A
gc.collect()
self.assertIsNone(r())
class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
......
......@@ -133,6 +133,8 @@ Core and Builtins
Library
-------
- Issue #25935: Garbage collector now breaks reference loops with OrderedDict.
- Issue #16620: Fixed AttributeError in msilib.Directory.glob().
- Issue #26013: Added compatibility with broken protocol 2 pickles created
......
......@@ -772,19 +772,17 @@ _odict_clear_nodes(PyODictObject *od)
{
_ODictNode *node, *next;
if (!_odict_EMPTY(od)) {
node = _odict_FIRST(od);
while (node != NULL) {
next = _odictnode_NEXT(node);
_odictnode_DEALLOC(node);
node = next;
}
_odict_FIRST(od) = NULL;
_odict_LAST(od) = NULL;
}
_odict_free_fast_nodes(od);
od->od_fast_nodes = NULL;
node = _odict_FIRST(od);
_odict_FIRST(od) = NULL;
_odict_LAST(od) = NULL;
while (node != NULL) {
next = _odictnode_NEXT(node);
_odictnode_DEALLOC(node);
node = next;
}
}
/* There isn't any memory management of nodes past this point. */
......@@ -1233,8 +1231,6 @@ odict_clear(register PyODictObject *od)
{
PyDict_Clear((PyObject *)od);
_odict_clear_nodes(od);
_odict_FIRST(od) = NULL;
_odict_LAST(od) = NULL;
if (_odict_resize(od) < 0)
return NULL;
Py_RETURN_NONE;
......@@ -1556,8 +1552,13 @@ PyDoc_STRVAR(odict_doc,
static int
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));
}
return PyDict_Type.tp_traverse((PyObject *)od, visit, arg);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment