blob: 8e93816d965877efb289470ce9d91ca197419a05 [file] [log] [blame]
Victor Stinner076fc872015-10-03 00:20:56 +02001import errno
Victor Stinner3844fe52015-09-26 10:38:01 +02002import os
3import re
4import sys
5import warnings
6from inspect import isabstract
7from test import support
8
9
Victor Stinner076fc872015-10-03 00:20:56 +020010try:
11 MAXFD = os.sysconf("SC_OPEN_MAX")
12except Exception:
13 MAXFD = 256
14
15
16def fd_count():
17 """Count the number of open file descriptors"""
18 if sys.platform.startswith(('linux', 'freebsd')):
19 try:
20 names = os.listdir("/proc/self/fd")
21 return len(names)
22 except FileNotFoundError:
23 pass
24
25 count = 0
26 for fd in range(MAXFD):
27 try:
28 # Prefer dup() over fstat(). fstat() can require input/output
29 # whereas dup() doesn't.
30 fd2 = os.dup(fd)
31 except OSError as e:
32 if e.errno != errno.EBADF:
33 raise
34 else:
35 os.close(fd2)
36 count += 1
37 return count
38
39
Victor Stinner3844fe52015-09-26 10:38:01 +020040def dash_R(the_module, test, indirect_test, huntrleaks):
41 """Run a test multiple times, looking for reference leaks.
42
43 Returns:
44 False if the test didn't leak references; True if we detected refleaks.
45 """
46 # This code is hackish and inelegant, but it seems to do the job.
47 import copyreg
48 import collections.abc
49
50 if not hasattr(sys, 'gettotalrefcount'):
51 raise Exception("Tracking reference leaks requires a debug build "
52 "of Python")
53
54 # Save current values for dash_R_cleanup() to restore.
55 fs = warnings.filters[:]
56 ps = copyreg.dispatch_table.copy()
57 pic = sys.path_importer_cache.copy()
58 try:
59 import zipimport
60 except ImportError:
61 zdc = None # Run unmodified on platforms without zipimport support
62 else:
63 zdc = zipimport._zip_directory_cache.copy()
64 abcs = {}
65 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
66 if not isabstract(abc):
67 continue
68 for obj in abc.__subclasses__() + [abc]:
69 abcs[obj] = obj._abc_registry.copy()
70
71 nwarmup, ntracked, fname = huntrleaks
72 fname = os.path.join(support.SAVEDCWD, fname)
73 repcount = nwarmup + ntracked
74 rc_deltas = [0] * repcount
75 alloc_deltas = [0] * repcount
Victor Stinner076fc872015-10-03 00:20:56 +020076 fd_deltas = [0] * repcount
Victor Stinner3844fe52015-09-26 10:38:01 +020077
78 print("beginning", repcount, "repetitions", file=sys.stderr)
Victor Stinnerf33536c2015-09-30 00:48:27 +020079 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
80 flush=True)
Victor Stinner9a142142015-09-30 13:51:17 +020081 # initialize variables to make pyflakes quiet
Victor Stinner076fc872015-10-03 00:20:56 +020082 rc_before = alloc_before = fd_before = 0
Victor Stinner3844fe52015-09-26 10:38:01 +020083 for i in range(repcount):
84 indirect_test()
Victor Stinner076fc872015-10-03 00:20:56 +020085 alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc,
86 abcs)
Victor Stinner17a63e22017-02-08 13:06:08 +010087 print('.', end='', file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +020088 if i >= nwarmup:
89 rc_deltas[i] = rc_after - rc_before
90 alloc_deltas[i] = alloc_after - alloc_before
Victor Stinner076fc872015-10-03 00:20:56 +020091 fd_deltas[i] = fd_after - fd_before
92 alloc_before = alloc_after
93 rc_before = rc_after
94 fd_before = fd_after
Victor Stinner3844fe52015-09-26 10:38:01 +020095 print(file=sys.stderr)
Victor Stinner48b5c422017-06-27 02:02:04 +020096
Victor Stinner3844fe52015-09-26 10:38:01 +020097 # These checkers return False on success, True on failure
98 def check_rc_deltas(deltas):
Victor Stinnerbeeca6e2017-06-29 10:32:49 +020099 # Checker for reference counters and memomry blocks.
100 #
Victor Stinner48b5c422017-06-27 02:02:04 +0200101 # bpo-30776: Try to ignore false positives:
102 #
103 # [3, 0, 0]
104 # [0, 1, 0]
105 # [8, -8, 1]
106 #
107 # Expected leaks:
108 #
109 # [5, 5, 6]
110 # [10, 1, 1]
111 return all(delta >= 1 for delta in deltas)
112
Victor Stinner48b5c422017-06-27 02:02:04 +0200113 def check_fd_deltas(deltas):
114 return any(deltas)
115
Victor Stinner3844fe52015-09-26 10:38:01 +0200116 failed = False
117 for deltas, item_name, checker in [
118 (rc_deltas, 'references', check_rc_deltas),
Victor Stinnerbeeca6e2017-06-29 10:32:49 +0200119 (alloc_deltas, 'memory blocks', check_rc_deltas),
Victor Stinner48b5c422017-06-27 02:02:04 +0200120 (fd_deltas, 'file descriptors', check_fd_deltas)
121 ]:
122 # ignore warmup runs
123 deltas = deltas[nwarmup:]
Victor Stinner3844fe52015-09-26 10:38:01 +0200124 if checker(deltas):
125 msg = '%s leaked %s %s, sum=%s' % (
Victor Stinner48b5c422017-06-27 02:02:04 +0200126 test, deltas, item_name, sum(deltas))
Victor Stinnerf33536c2015-09-30 00:48:27 +0200127 print(msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200128 with open(fname, "a") as refrep:
129 print(msg, file=refrep)
130 refrep.flush()
131 failed = True
132 return failed
133
134
135def dash_R_cleanup(fs, ps, pic, zdc, abcs):
136 import gc, copyreg
Serhiy Storchaka83910262016-11-11 11:46:44 +0200137 import collections.abc
Victor Stinner3844fe52015-09-26 10:38:01 +0200138 from weakref import WeakSet
139
Victor Stinner3844fe52015-09-26 10:38:01 +0200140 # Restore some original values.
141 warnings.filters[:] = fs
142 copyreg.dispatch_table.clear()
143 copyreg.dispatch_table.update(ps)
144 sys.path_importer_cache.clear()
145 sys.path_importer_cache.update(pic)
146 try:
147 import zipimport
148 except ImportError:
149 pass # Run unmodified on platforms without zipimport support
150 else:
151 zipimport._zip_directory_cache.clear()
152 zipimport._zip_directory_cache.update(zdc)
153
154 # clear type cache
155 sys._clear_type_cache()
156
157 # Clear ABC registries, restoring previously saved ABC registries.
Ivan Levkivskyi7acffa22017-03-05 19:15:20 +0100158 abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
159 abs_classes = filter(isabstract, abs_classes)
160 if 'typing' in sys.modules:
161 t = sys.modules['typing']
162 # These classes require special treatment because they do not appear
163 # in direct subclasses of collections.abc classes
164 abs_classes = list(abs_classes) + [t.ChainMap, t.Counter, t.DefaultDict]
165 for abc in abs_classes:
Victor Stinner3844fe52015-09-26 10:38:01 +0200166 for obj in abc.__subclasses__() + [abc]:
167 obj._abc_registry = abcs.get(obj, WeakSet()).copy()
168 obj._abc_cache.clear()
169 obj._abc_negative_cache.clear()
170
Serhiy Storchaka83910262016-11-11 11:46:44 +0200171 clear_caches()
172
173 # Collect cyclic trash and read memory statistics immediately after.
174 func1 = sys.getallocatedblocks
175 func2 = sys.gettotalrefcount
176 gc.collect()
177 return func1(), func2(), fd_count()
178
179
180def clear_caches():
181 import gc
182
183 # Clear the warnings registry, so they can be displayed again
184 for mod in sys.modules.values():
185 if hasattr(mod, '__warningregistry__'):
186 del mod.__warningregistry__
187
Victor Stinner3844fe52015-09-26 10:38:01 +0200188 # Flush standard output, so that buffered data is sent to the OS and
189 # associated Python objects are reclaimed.
190 for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
191 if stream is not None:
192 stream.flush()
193
194 # Clear assorted module caches.
Serhiy Storchaka83910262016-11-11 11:46:44 +0200195 # Don't worry about resetting the cache if the module is not loaded
Victor Stinner3844fe52015-09-26 10:38:01 +0200196 try:
Serhiy Storchaka83910262016-11-11 11:46:44 +0200197 distutils_dir_util = sys.modules['distutils.dir_util']
198 except KeyError:
199 pass
200 else:
201 distutils_dir_util._path_created.clear()
202 re.purge()
203
204 try:
205 _strptime = sys.modules['_strptime']
206 except KeyError:
207 pass
208 else:
209 _strptime._regex_cache.clear()
210
211 try:
212 urllib_parse = sys.modules['urllib.parse']
213 except KeyError:
214 pass
215 else:
216 urllib_parse.clear_cache()
217
218 try:
219 urllib_request = sys.modules['urllib.request']
220 except KeyError:
221 pass
222 else:
223 urllib_request.urlcleanup()
224
225 try:
226 linecache = sys.modules['linecache']
227 except KeyError:
228 pass
229 else:
230 linecache.clearcache()
231
232 try:
233 mimetypes = sys.modules['mimetypes']
234 except KeyError:
235 pass
236 else:
237 mimetypes._default_mime_types()
238
239 try:
240 filecmp = sys.modules['filecmp']
241 except KeyError:
242 pass
243 else:
244 filecmp._cache.clear()
245
246 try:
247 struct = sys.modules['struct']
248 except KeyError:
249 pass
250 else:
251 struct._clearcache()
252
253 try:
254 doctest = sys.modules['doctest']
255 except KeyError:
256 pass
257 else:
258 doctest.master = None
259
260 try:
261 ctypes = sys.modules['ctypes']
262 except KeyError:
Victor Stinner3844fe52015-09-26 10:38:01 +0200263 pass
264 else:
265 ctypes._reset_cache()
266
Serhiy Storchaka04c954d2016-11-09 23:51:54 +0200267 try:
268 typing = sys.modules['typing']
269 except KeyError:
270 pass
271 else:
272 for f in typing._cleanups:
273 f()
274
Victor Stinner3844fe52015-09-26 10:38:01 +0200275 gc.collect()
Victor Stinner3844fe52015-09-26 10:38:01 +0200276
277
278def warm_caches():
279 # char cache
280 s = bytes(range(256))
281 for i in range(256):
282 s[i:i+1]
283 # unicode cache
Victor Stinner9a142142015-09-30 13:51:17 +0200284 [chr(i) for i in range(256)]
Victor Stinner3844fe52015-09-26 10:38:01 +0200285 # int cache
Victor Stinner9a142142015-09-30 13:51:17 +0200286 list(range(-5, 257))