Skip to content

Commit daff555

Browse files
committed
gh-155981: Store refleak deltas in arrays
Store per-run deltas in array objects rather than lists of pooled integers. Large, unique deltas could otherwise grow int_pool and make the refleak checker report its own retained integers as reference leaks.
1 parent a7bb524 commit daff555

1 file changed

Lines changed: 14 additions & 18 deletions

File tree

Lib/test/libregrtest/refleak.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import sys
33
import warnings
4+
from array import array
45
from inspect import isabstract
56
from typing import Any
67
import linecache
@@ -100,24 +101,20 @@ def runtest_refleak(test_name, test_func,
100101
for obj in ByteString.__subclasses__() + [ByteString]: # type: ignore[attr-defined]
101102
abcs[obj] = _get_dump(obj)[0]
102103

103-
# bpo-31217: Integer pool to get a single integer object for the same
104-
# value. The pool is used to prevent false alarm when checking for memory
105-
# block leaks. Fill the pool with values in -1000..1000 which are the most
106-
# common (reference, memory block, file descriptor) differences.
107-
int_pool = {value: value for value in range(-1000, 1000)}
108-
def get_pooled_int(value):
109-
return int_pool.setdefault(value, value)
110-
111104
warmups = hunt_refleak.warmups
112105
runs = hunt_refleak.runs
113106
filename = hunt_refleak.filename
114107
repcount = warmups + runs
115108

116-
# Pre-allocate to ensure that the loop doesn't allocate anything new
109+
# Pre-allocate to ensure that the loop doesn't allocate anything new.
110+
# Store the deltas as raw values in arrays rather than as int objects in
111+
# lists: each unique delta stored as an object would live until the end of
112+
# the loop and show up in the following repetition's reference and memory
113+
# block deltas (bpo-31217, gh-155981).
117114
rep_range = list(range(repcount))
118-
rc_deltas = [0] * repcount
119-
alloc_deltas = [0] * repcount
120-
fd_deltas = [0] * repcount
115+
rc_deltas = array('q', [0]) * repcount
116+
alloc_deltas = array('q', [0]) * repcount
117+
fd_deltas = array('q', [0]) * repcount
121118
getallocatedblocks = sys.getallocatedblocks
122119
gettotalrefcount = sys.gettotalrefcount
123120
getunicodeinternedsize = sys.getunicodeinternedsize
@@ -161,12 +158,11 @@ def get_pooled_int(value):
161158
rc_after = gettotalrefcount()
162159
fd_after = fd_count()
163160

164-
rc_deltas[i] = get_pooled_int(rc_after - rc_before)
165-
alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before)
166-
fd_deltas[i] = get_pooled_int(fd_after - fd_before)
161+
rc_deltas[i] = rc_after - rc_before
162+
alloc_deltas[i] = alloc_after - alloc_before
163+
fd_deltas[i] = fd_after - fd_before
167164

168165
if not quiet:
169-
# use max, not sum, so total_leaks is one of the pooled ints
170166
total_leaks = max(rc_deltas[i], alloc_deltas[i], fd_deltas[i])
171167
if total_leaks <= 0:
172168
symbol = '.'
@@ -217,8 +213,8 @@ def check_fd_deltas(deltas):
217213
(alloc_deltas, 'memory blocks', check_rc_deltas),
218214
(fd_deltas, 'file descriptors', check_fd_deltas)
219215
]:
220-
# ignore warmup runs
221-
deltas = deltas[warmups:]
216+
# ignore warmup runs; convert to a list for reporting
217+
deltas = list(deltas[warmups:])
222218
failing = checker(deltas)
223219
suspicious = any(deltas)
224220
if failing or suspicious:

0 commit comments

Comments
 (0)