bpo-42536: GC track recycled tuples (GH-23623)

Several built-in and standard library types now ensure that their internal result tuples are always tracked by the garbage collector:

- collections.OrderedDict.items
- dict.items
- enumerate
- functools.reduce
- itertools.combinations
- itertools.combinations_with_replacement
- itertools.permutations
- itertools.product
- itertools.zip_longest
- zip

Previously, they could have become untracked by a prior garbage collection.
This commit is contained in:
Brandt Bucher 2020-12-04 19:45:57 -08:00 committed by GitHub
parent 2de5097ba4
commit 226a012d1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 192 additions and 0 deletions

View file

@ -2,6 +2,7 @@ import unittest
import operator
import sys
import pickle
import gc
from test import support
@ -134,6 +135,18 @@ class EnumerateTestCase(unittest.TestCase, PickleTest):
self.assertEqual(len(set(map(id, list(enumerate(self.seq))))), len(self.seq))
self.assertEqual(len(set(map(id, enumerate(self.seq)))), min(1,len(self.seq)))
@support.cpython_only
def test_enumerate_result_gc(self):
# bpo-42536: enumerate's tuple-reuse speed trick breaks the GC's
# assumptions about what can be untracked. Make sure we re-track result
# tuples whenever we reuse them.
it = self.enum([[]])
gc.collect()
# That GC collection probably untracked the recycled internal result
# tuple, which is initialized to (None, None). Make sure it's re-tracked
# when it's mutated and returned from __next__:
self.assertTrue(gc.is_tracked(next(it)))
class MyEnum(enumerate):
pass