blob: b56a84856d14fdf5394b4f07d3941573ec01a666 [file] [log] [blame]
Victor Stinner3844fe52015-09-26 10:38:01 +02001import os
2import re
3import sys
4import warnings
5from inspect import isabstract
6from test import support
Hai Shifcce8c62020-08-08 05:55:35 +08007from test.support import os_helper
Victor Stinner10417dd2021-03-23 00:17:05 +01008from test.libregrtest.utils import clear_caches
Hai Shifcce8c62020-08-08 05:55:35 +08009
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000010try:
11 from _abc import _get_dump
12except ImportError:
Victor Stinner79b5d292019-04-09 01:36:34 +020013 import weakref
14
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000015 def _get_dump(cls):
Victor Stinner79b5d292019-04-09 01:36:34 +020016 # Reimplement _get_dump() for pure-Python implementation of
17 # the abc module (Lib/_py_abc.py)
18 registry_weakrefs = set(weakref.ref(obj) for obj in cls._abc_registry)
19 return (registry_weakrefs, cls._abc_cache,
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000020 cls._abc_negative_cache, cls._abc_negative_cache_version)
Victor Stinner3844fe52015-09-26 10:38:01 +020021
22
Victor Stinner4d299832019-04-26 04:08:53 +020023def dash_R(ns, test_name, test_func):
Victor Stinner3844fe52015-09-26 10:38:01 +020024 """Run a test multiple times, looking for reference leaks.
25
26 Returns:
27 False if the test didn't leak references; True if we detected refleaks.
28 """
29 # This code is hackish and inelegant, but it seems to do the job.
30 import copyreg
31 import collections.abc
32
33 if not hasattr(sys, 'gettotalrefcount'):
34 raise Exception("Tracking reference leaks requires a debug build "
35 "of Python")
36
Victor Stinner5aaac942019-04-09 14:23:47 +020037 # Avoid false positives due to various caches
38 # filling slowly with random data:
39 warm_caches()
40
Victor Stinner3844fe52015-09-26 10:38:01 +020041 # Save current values for dash_R_cleanup() to restore.
42 fs = warnings.filters[:]
43 ps = copyreg.dispatch_table.copy()
44 pic = sys.path_importer_cache.copy()
45 try:
46 import zipimport
47 except ImportError:
48 zdc = None # Run unmodified on platforms without zipimport support
49 else:
50 zdc = zipimport._zip_directory_cache.copy()
51 abcs = {}
52 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
53 if not isabstract(abc):
54 continue
55 for obj in abc.__subclasses__() + [abc]:
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000056 abcs[obj] = _get_dump(obj)[0]
Victor Stinner3844fe52015-09-26 10:38:01 +020057
Victor Stinner6c2feab2017-09-01 13:05:27 +020058 # bpo-31217: Integer pool to get a single integer object for the same
59 # value. The pool is used to prevent false alarm when checking for memory
60 # block leaks. Fill the pool with values in -1000..1000 which are the most
61 # common (reference, memory block, file descriptor) differences.
62 int_pool = {value: value for value in range(-1000, 1000)}
63 def get_pooled_int(value):
64 return int_pool.setdefault(value, value)
65
Victor Stinner5aaac942019-04-09 14:23:47 +020066 nwarmup, ntracked, fname = ns.huntrleaks
Hai Shifcce8c62020-08-08 05:55:35 +080067 fname = os.path.join(os_helper.SAVEDCWD, fname)
Victor Stinner3844fe52015-09-26 10:38:01 +020068 repcount = nwarmup + ntracked
Victor Stinner5aaac942019-04-09 14:23:47 +020069
70 # Pre-allocate to ensure that the loop doesn't allocate anything new
71 rep_range = list(range(repcount))
Victor Stinner3844fe52015-09-26 10:38:01 +020072 rc_deltas = [0] * repcount
73 alloc_deltas = [0] * repcount
Victor Stinner076fc872015-10-03 00:20:56 +020074 fd_deltas = [0] * repcount
Victor Stinner5aaac942019-04-09 14:23:47 +020075 getallocatedblocks = sys.getallocatedblocks
76 gettotalrefcount = sys.gettotalrefcount
Hai Shifcce8c62020-08-08 05:55:35 +080077 fd_count = os_helper.fd_count
Victor Stinner3844fe52015-09-26 10:38:01 +020078
Victor Stinner9a142142015-09-30 13:51:17 +020079 # initialize variables to make pyflakes quiet
Victor Stinner076fc872015-10-03 00:20:56 +020080 rc_before = alloc_before = fd_before = 0
Victor Stinner5aaac942019-04-09 14:23:47 +020081
82 if not ns.quiet:
83 print("beginning", repcount, "repetitions", file=sys.stderr)
84 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
85 flush=True)
86
Victor Stinnerbb444782019-04-09 18:26:16 +020087 dash_R_cleanup(fs, ps, pic, zdc, abcs)
88
Victor Stinner5aaac942019-04-09 14:23:47 +020089 for i in rep_range:
90 test_func()
91 dash_R_cleanup(fs, ps, pic, zdc, abcs)
92
Victor Stinnerbb444782019-04-09 18:26:16 +020093 # dash_R_cleanup() ends with collecting cyclic trash:
94 # read memory statistics immediately after.
Victor Stinner5aaac942019-04-09 14:23:47 +020095 alloc_after = getallocatedblocks()
96 rc_after = gettotalrefcount()
97 fd_after = fd_count()
98
99 if not ns.quiet:
100 print('.', end='', file=sys.stderr, flush=True)
101
102 rc_deltas[i] = get_pooled_int(rc_after - rc_before)
103 alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before)
104 fd_deltas[i] = get_pooled_int(fd_after - fd_before)
105
Victor Stinner076fc872015-10-03 00:20:56 +0200106 alloc_before = alloc_after
107 rc_before = rc_after
108 fd_before = fd_after
Victor Stinner5aaac942019-04-09 14:23:47 +0200109
110 if not ns.quiet:
111 print(file=sys.stderr)
Victor Stinner48b5c422017-06-27 02:02:04 +0200112
Victor Stinner3844fe52015-09-26 10:38:01 +0200113 # These checkers return False on success, True on failure
114 def check_rc_deltas(deltas):
Christian Clausscfca4a62021-10-07 17:49:47 +0200115 # Checker for reference counters and memory blocks.
Victor Stinnerbeeca6e2017-06-29 10:32:49 +0200116 #
Victor Stinner48b5c422017-06-27 02:02:04 +0200117 # bpo-30776: Try to ignore false positives:
118 #
119 # [3, 0, 0]
120 # [0, 1, 0]
121 # [8, -8, 1]
122 #
123 # Expected leaks:
124 #
125 # [5, 5, 6]
126 # [10, 1, 1]
127 return all(delta >= 1 for delta in deltas)
128
Victor Stinner48b5c422017-06-27 02:02:04 +0200129 def check_fd_deltas(deltas):
130 return any(deltas)
131
Victor Stinner3844fe52015-09-26 10:38:01 +0200132 failed = False
133 for deltas, item_name, checker in [
134 (rc_deltas, 'references', check_rc_deltas),
Victor Stinnerbeeca6e2017-06-29 10:32:49 +0200135 (alloc_deltas, 'memory blocks', check_rc_deltas),
Victor Stinner48b5c422017-06-27 02:02:04 +0200136 (fd_deltas, 'file descriptors', check_fd_deltas)
137 ]:
138 # ignore warmup runs
139 deltas = deltas[nwarmup:]
Victor Stinner3844fe52015-09-26 10:38:01 +0200140 if checker(deltas):
141 msg = '%s leaked %s %s, sum=%s' % (
Victor Stinner5aaac942019-04-09 14:23:47 +0200142 test_name, deltas, item_name, sum(deltas))
Victor Stinnerf33536c2015-09-30 00:48:27 +0200143 print(msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200144 with open(fname, "a") as refrep:
145 print(msg, file=refrep)
146 refrep.flush()
147 failed = True
148 return failed
149
150
151def dash_R_cleanup(fs, ps, pic, zdc, abcs):
Victor Stinner5aaac942019-04-09 14:23:47 +0200152 import copyreg
Serhiy Storchaka83910262016-11-11 11:46:44 +0200153 import collections.abc
Victor Stinner3844fe52015-09-26 10:38:01 +0200154
Victor Stinner3844fe52015-09-26 10:38:01 +0200155 # Restore some original values.
156 warnings.filters[:] = fs
157 copyreg.dispatch_table.clear()
158 copyreg.dispatch_table.update(ps)
159 sys.path_importer_cache.clear()
160 sys.path_importer_cache.update(pic)
161 try:
162 import zipimport
163 except ImportError:
164 pass # Run unmodified on platforms without zipimport support
165 else:
166 zipimport._zip_directory_cache.clear()
167 zipimport._zip_directory_cache.update(zdc)
168
169 # clear type cache
170 sys._clear_type_cache()
171
172 # Clear ABC registries, restoring previously saved ABC registries.
Ivan Levkivskyi7acffa22017-03-05 19:15:20 +0100173 abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
174 abs_classes = filter(isabstract, abs_classes)
Ivan Levkivskyi7acffa22017-03-05 19:15:20 +0100175 for abc in abs_classes:
Victor Stinner3844fe52015-09-26 10:38:01 +0200176 for obj in abc.__subclasses__() + [abc]:
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000177 for ref in abcs.get(obj, set()):
178 if ref() is not None:
179 obj.register(ref())
180 obj._abc_caches_clear()
Victor Stinner3844fe52015-09-26 10:38:01 +0200181
Serhiy Storchaka83910262016-11-11 11:46:44 +0200182 clear_caches()
183
Serhiy Storchaka83910262016-11-11 11:46:44 +0200184
Victor Stinner3844fe52015-09-26 10:38:01 +0200185def warm_caches():
186 # char cache
187 s = bytes(range(256))
188 for i in range(256):
189 s[i:i+1]
190 # unicode cache
Victor Stinner9a142142015-09-30 13:51:17 +0200191 [chr(i) for i in range(256)]
Victor Stinner3844fe52015-09-26 10:38:01 +0200192 # int cache
Victor Stinner9a142142015-09-30 13:51:17 +0200193 list(range(-5, 257))