mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	Issue #25935: Garbage collector now breaks reference loops with OrderedDict.
This commit is contained in:
		
						commit
						4918b47c64
					
				
					 3 changed files with 29 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -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 @@ def test_dict_update(self):
 | 
			
		|||
        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…
	
	Add table
		Add a link
		
	
		Reference in a new issue