mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
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:
parent
2de5097ba4
commit
226a012d1c
12 changed files with 192 additions and 0 deletions
|
@ -12,6 +12,8 @@ from functools import reduce
|
|||
import sys
|
||||
import struct
|
||||
import threading
|
||||
import gc
|
||||
|
||||
maxsize = support.MAX_Py_ssize_t
|
||||
minsize = -maxsize-1
|
||||
|
||||
|
@ -1573,6 +1575,51 @@ class TestBasicOps(unittest.TestCase):
|
|||
self.assertRaises(StopIteration, next, f(lambda x:x, []))
|
||||
self.assertRaises(StopIteration, next, f(lambda x:x, StopNow()))
|
||||
|
||||
@support.cpython_only
|
||||
def test_combinations_result_gc(self):
|
||||
# bpo-42536: combinations'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 = combinations([None, []], 1)
|
||||
next(it)
|
||||
gc.collect()
|
||||
# That GC collection probably untracked the recycled internal result
|
||||
# tuple, which has the value (None,). Make sure it's re-tracked when
|
||||
# it's mutated and returned from __next__:
|
||||
self.assertTrue(gc.is_tracked(next(it)))
|
||||
|
||||
@support.cpython_only
|
||||
def test_combinations_with_replacement_result_gc(self):
|
||||
# Ditto for combinations_with_replacement.
|
||||
it = combinations_with_replacement([None, []], 1)
|
||||
next(it)
|
||||
gc.collect()
|
||||
self.assertTrue(gc.is_tracked(next(it)))
|
||||
|
||||
@support.cpython_only
|
||||
def test_permutations_result_gc(self):
|
||||
# Ditto for permutations.
|
||||
it = permutations([None, []], 1)
|
||||
next(it)
|
||||
gc.collect()
|
||||
self.assertTrue(gc.is_tracked(next(it)))
|
||||
|
||||
@support.cpython_only
|
||||
def test_product_result_gc(self):
|
||||
# Ditto for product.
|
||||
it = product([None, []])
|
||||
next(it)
|
||||
gc.collect()
|
||||
self.assertTrue(gc.is_tracked(next(it)))
|
||||
|
||||
@support.cpython_only
|
||||
def test_zip_longest_result_gc(self):
|
||||
# Ditto for zip_longest.
|
||||
it = zip_longest([[]])
|
||||
gc.collect()
|
||||
self.assertTrue(gc.is_tracked(next(it)))
|
||||
|
||||
|
||||
class TestExamples(unittest.TestCase):
|
||||
|
||||
def test_accumulate(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue