blob: efe52107cb4d1f4c7105a048ace6e6e3d02783ff [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
10def dash_R(the_module, test, indirect_test, huntrleaks):
11 """Run a test multiple times, looking for reference leaks.
12
13 Returns:
14 False if the test didn't leak references; True if we detected refleaks.
15 """
16 # This code is hackish and inelegant, but it seems to do the job.
17 import copyreg
18 import collections.abc
19
20 if not hasattr(sys, 'gettotalrefcount'):
21 raise Exception("Tracking reference leaks requires a debug build "
22 "of Python")
23
24 # Save current values for dash_R_cleanup() to restore.
25 fs = warnings.filters[:]
26 ps = copyreg.dispatch_table.copy()
27 pic = sys.path_importer_cache.copy()
28 try:
29 import zipimport
30 except ImportError:
31 zdc = None # Run unmodified on platforms without zipimport support
32 else:
33 zdc = zipimport._zip_directory_cache.copy()
34 abcs = {}
35 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
36 if not isabstract(abc):
37 continue
38 for obj in abc.__subclasses__() + [abc]:
39 abcs[obj] = obj._abc_registry.copy()
40
41 nwarmup, ntracked, fname = huntrleaks
42 fname = os.path.join(support.SAVEDCWD, fname)
43 repcount = nwarmup + ntracked
44 rc_deltas = [0] * repcount
45 alloc_deltas = [0] * repcount
Victor Stinner076fc872015-10-03 00:20:56 +020046 fd_deltas = [0] * repcount
Victor Stinner3844fe52015-09-26 10:38:01 +020047
48 print("beginning", repcount, "repetitions", file=sys.stderr)
Victor Stinnerf33536c2015-09-30 00:48:27 +020049 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
50 flush=True)
Victor Stinner9a142142015-09-30 13:51:17 +020051 # initialize variables to make pyflakes quiet
Victor Stinner076fc872015-10-03 00:20:56 +020052 rc_before = alloc_before = fd_before = 0
Victor Stinner3844fe52015-09-26 10:38:01 +020053 for i in range(repcount):
54 indirect_test()
Victor Stinner076fc872015-10-03 00:20:56 +020055 alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc,
56 abcs)
Victor Stinner17a63e22017-02-08 13:06:08 +010057 print('.', end='', file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +020058 if i >= nwarmup:
59 rc_deltas[i] = rc_after - rc_before
60 alloc_deltas[i] = alloc_after - alloc_before
Victor Stinner076fc872015-10-03 00:20:56 +020061 fd_deltas[i] = fd_after - fd_before
62 alloc_before = alloc_after
63 rc_before = rc_after
64 fd_before = fd_after
Victor Stinner3844fe52015-09-26 10:38:01 +020065 print(file=sys.stderr)
Victor Stinner48b5c422017-06-27 02:02:04 +020066
Victor Stinner3844fe52015-09-26 10:38:01 +020067 # These checkers return False on success, True on failure
68 def check_rc_deltas(deltas):
Victor Stinnerbeeca6e2017-06-29 10:32:49 +020069 # Checker for reference counters and memomry blocks.
70 #
Victor Stinner48b5c422017-06-27 02:02:04 +020071 # bpo-30776: Try to ignore false positives:
72 #
73 # [3, 0, 0]
74 # [0, 1, 0]
75 # [8, -8, 1]
76 #
77 # Expected leaks:
78 #
79 # [5, 5, 6]
80 # [10, 1, 1]
81 return all(delta >= 1 for delta in deltas)
82
Victor Stinner48b5c422017-06-27 02:02:04 +020083 def check_fd_deltas(deltas):
84 return any(deltas)
85
Victor Stinner3844fe52015-09-26 10:38:01 +020086 failed = False
87 for deltas, item_name, checker in [
88 (rc_deltas, 'references', check_rc_deltas),
Victor Stinnerbeeca6e2017-06-29 10:32:49 +020089 (alloc_deltas, 'memory blocks', check_rc_deltas),
Victor Stinner48b5c422017-06-27 02:02:04 +020090 (fd_deltas, 'file descriptors', check_fd_deltas)
91 ]:
92 # ignore warmup runs
93 deltas = deltas[nwarmup:]
Victor Stinner3844fe52015-09-26 10:38:01 +020094 if checker(deltas):
95 msg = '%s leaked %s %s, sum=%s' % (
Victor Stinner48b5c422017-06-27 02:02:04 +020096 test, deltas, item_name, sum(deltas))
Victor Stinnerf33536c2015-09-30 00:48:27 +020097 print(msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +020098 with open(fname, "a") as refrep:
99 print(msg, file=refrep)
100 refrep.flush()
101 failed = True
102 return failed
103
104
105def dash_R_cleanup(fs, ps, pic, zdc, abcs):
106 import gc, copyreg
Serhiy Storchaka83910262016-11-11 11:46:44 +0200107 import collections.abc
Victor Stinner3844fe52015-09-26 10:38:01 +0200108 from weakref import WeakSet
109
Victor Stinner3844fe52015-09-26 10:38:01 +0200110 # Restore some original values.
111 warnings.filters[:] = fs
112 copyreg.dispatch_table.clear()
113 copyreg.dispatch_table.update(ps)
114 sys.path_importer_cache.clear()
115 sys.path_importer_cache.update(pic)
116 try:
117 import zipimport
118 except ImportError:
119 pass # Run unmodified on platforms without zipimport support
120 else:
121 zipimport._zip_directory_cache.clear()
122 zipimport._zip_directory_cache.update(zdc)
123
124 # clear type cache
125 sys._clear_type_cache()
126
127 # Clear ABC registries, restoring previously saved ABC registries.
Ivan Levkivskyi7acffa22017-03-05 19:15:20 +0100128 abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
129 abs_classes = filter(isabstract, abs_classes)
130 if 'typing' in sys.modules:
131 t = sys.modules['typing']
132 # These classes require special treatment because they do not appear
133 # in direct subclasses of collections.abc classes
134 abs_classes = list(abs_classes) + [t.ChainMap, t.Counter, t.DefaultDict]
135 for abc in abs_classes:
Victor Stinner3844fe52015-09-26 10:38:01 +0200136 for obj in abc.__subclasses__() + [abc]:
137 obj._abc_registry = abcs.get(obj, WeakSet()).copy()
138 obj._abc_cache.clear()
139 obj._abc_negative_cache.clear()
140
Serhiy Storchaka83910262016-11-11 11:46:44 +0200141 clear_caches()
142
143 # Collect cyclic trash and read memory statistics immediately after.
144 func1 = sys.getallocatedblocks
145 func2 = sys.gettotalrefcount
146 gc.collect()
Antoine Pitrou896145d2017-07-22 13:22:54 +0200147 return func1(), func2(), support.fd_count()
Serhiy Storchaka83910262016-11-11 11:46:44 +0200148
149
150def clear_caches():
151 import gc
152
153 # Clear the warnings registry, so they can be displayed again
154 for mod in sys.modules.values():
155 if hasattr(mod, '__warningregistry__'):
156 del mod.__warningregistry__
157
Victor Stinner3844fe52015-09-26 10:38:01 +0200158 # Flush standard output, so that buffered data is sent to the OS and
159 # associated Python objects are reclaimed.
160 for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
161 if stream is not None:
162 stream.flush()
163
164 # Clear assorted module caches.
Serhiy Storchaka83910262016-11-11 11:46:44 +0200165 # Don't worry about resetting the cache if the module is not loaded
Victor Stinner3844fe52015-09-26 10:38:01 +0200166 try:
Serhiy Storchaka83910262016-11-11 11:46:44 +0200167 distutils_dir_util = sys.modules['distutils.dir_util']
168 except KeyError:
169 pass
170 else:
171 distutils_dir_util._path_created.clear()
172 re.purge()
173
174 try:
175 _strptime = sys.modules['_strptime']
176 except KeyError:
177 pass
178 else:
179 _strptime._regex_cache.clear()
180
181 try:
182 urllib_parse = sys.modules['urllib.parse']
183 except KeyError:
184 pass
185 else:
186 urllib_parse.clear_cache()
187
188 try:
189 urllib_request = sys.modules['urllib.request']
190 except KeyError:
191 pass
192 else:
193 urllib_request.urlcleanup()
194
195 try:
196 linecache = sys.modules['linecache']
197 except KeyError:
198 pass
199 else:
200 linecache.clearcache()
201
202 try:
203 mimetypes = sys.modules['mimetypes']
204 except KeyError:
205 pass
206 else:
207 mimetypes._default_mime_types()
208
209 try:
210 filecmp = sys.modules['filecmp']
211 except KeyError:
212 pass
213 else:
214 filecmp._cache.clear()
215
216 try:
217 struct = sys.modules['struct']
218 except KeyError:
219 pass
220 else:
221 struct._clearcache()
222
223 try:
224 doctest = sys.modules['doctest']
225 except KeyError:
226 pass
227 else:
228 doctest.master = None
229
230 try:
231 ctypes = sys.modules['ctypes']
232 except KeyError:
Victor Stinner3844fe52015-09-26 10:38:01 +0200233 pass
234 else:
235 ctypes._reset_cache()
236
Serhiy Storchaka04c954d2016-11-09 23:51:54 +0200237 try:
238 typing = sys.modules['typing']
239 except KeyError:
240 pass
241 else:
242 for f in typing._cleanups:
243 f()
244
Victor Stinner3844fe52015-09-26 10:38:01 +0200245 gc.collect()
Victor Stinner3844fe52015-09-26 10:38:01 +0200246
247
248def warm_caches():
249 # char cache
250 s = bytes(range(256))
251 for i in range(256):
252 s[i:i+1]
253 # unicode cache
Victor Stinner9a142142015-09-30 13:51:17 +0200254 [chr(i) for i in range(256)]
Victor Stinner3844fe52015-09-26 10:38:01 +0200255 # int cache
Victor Stinner9a142142015-09-30 13:51:17 +0200256 list(range(-5, 257))