Issue #25935: Garbage collector now breaks reference loops with OrderedDict.
This commit is contained in:
commit
4918b47c64
|
@ -1,10 +1,12 @@
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue