1import os 2import re 3import sys 4import warnings 5from inspect import isabstract 6from test import support 7try: 8 from _abc import _get_dump 9except ImportError: 10 import weakref 11 12 def _get_dump(cls): 13 # Reimplement _get_dump() for pure-Python implementation of 14 # the abc module (Lib/_py_abc.py) 15 registry_weakrefs = set(weakref.ref(obj) for obj in cls._abc_registry) 16 return (registry_weakrefs, cls._abc_cache, 17 cls._abc_negative_cache, cls._abc_negative_cache_version) 18 19 20def dash_R(ns, test_name, test_func): 21 """Run a test multiple times, looking for reference leaks. 22 23 Returns: 24 False if the test didn't leak references; True if we detected refleaks. 25 """ 26 # This code is hackish and inelegant, but it seems to do the job. 27 import copyreg 28 import collections.abc 29 30 if not hasattr(sys, 'gettotalrefcount'): 31 raise Exception("Tracking reference leaks requires a debug build " 32 "of Python") 33 34 # Avoid false positives due to various caches 35 # filling slowly with random data: 36 warm_caches() 37 38 # Save current values for dash_R_cleanup() to restore. 39 fs = warnings.filters[:] 40 ps = copyreg.dispatch_table.copy() 41 pic = sys.path_importer_cache.copy() 42 try: 43 import zipimport 44 except ImportError: 45 zdc = None # Run unmodified on platforms without zipimport support 46 else: 47 zdc = zipimport._zip_directory_cache.copy() 48 abcs = {} 49 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: 50 if not isabstract(abc): 51 continue 52 for obj in abc.__subclasses__() + [abc]: 53 abcs[obj] = _get_dump(obj)[0] 54 55 # bpo-31217: Integer pool to get a single integer object for the same 56 # value. The pool is used to prevent false alarm when checking for memory 57 # block leaks. Fill the pool with values in -1000..1000 which are the most 58 # common (reference, memory block, file descriptor) differences. 59 int_pool = {value: value for value in range(-1000, 1000)} 60 def get_pooled_int(value): 61 return int_pool.setdefault(value, value) 62 63 nwarmup, ntracked, fname = ns.huntrleaks 64 fname = os.path.join(support.SAVEDCWD, fname) 65 repcount = nwarmup + ntracked 66 67 # Pre-allocate to ensure that the loop doesn't allocate anything new 68 rep_range = list(range(repcount)) 69 rc_deltas = [0] * repcount 70 alloc_deltas = [0] * repcount 71 fd_deltas = [0] * repcount 72 getallocatedblocks = sys.getallocatedblocks 73 gettotalrefcount = sys.gettotalrefcount 74 fd_count = support.fd_count 75 76 # initialize variables to make pyflakes quiet 77 rc_before = alloc_before = fd_before = 0 78 79 if not ns.quiet: 80 print("beginning", repcount, "repetitions", file=sys.stderr) 81 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr, 82 flush=True) 83 84 dash_R_cleanup(fs, ps, pic, zdc, abcs) 85 86 for i in rep_range: 87 test_func() 88 dash_R_cleanup(fs, ps, pic, zdc, abcs) 89 90 # dash_R_cleanup() ends with collecting cyclic trash: 91 # read memory statistics immediately after. 92 alloc_after = getallocatedblocks() 93 rc_after = gettotalrefcount() 94 fd_after = fd_count() 95 96 if not ns.quiet: 97 print('.', end='', file=sys.stderr, flush=True) 98 99 rc_deltas[i] = get_pooled_int(rc_after - rc_before) 100 alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before) 101 fd_deltas[i] = get_pooled_int(fd_after - fd_before) 102 103 alloc_before = alloc_after 104 rc_before = rc_after 105 fd_before = fd_after 106 107 if not ns.quiet: 108 print(file=sys.stderr) 109 110 # These checkers return False on success, True on failure 111 def check_rc_deltas(deltas): 112 # Checker for reference counters and memomry blocks. 113 # 114 # bpo-30776: Try to ignore false positives: 115 # 116 # [3, 0, 0] 117 # [0, 1, 0] 118 # [8, -8, 1] 119 # 120 # Expected leaks: 121 # 122 # [5, 5, 6] 123 # [10, 1, 1] 124 return all(delta >= 1 for delta in deltas) 125 126 def check_fd_deltas(deltas): 127 return any(deltas) 128 129 failed = False 130 for deltas, item_name, checker in [ 131 (rc_deltas, 'references', check_rc_deltas), 132 (alloc_deltas, 'memory blocks', check_rc_deltas), 133 (fd_deltas, 'file descriptors', check_fd_deltas) 134 ]: 135 # ignore warmup runs 136 deltas = deltas[nwarmup:] 137 if checker(deltas): 138 msg = '%s leaked %s %s, sum=%s' % ( 139 test_name, deltas, item_name, sum(deltas)) 140 print(msg, file=sys.stderr, flush=True) 141 with open(fname, "a") as refrep: 142 print(msg, file=refrep) 143 refrep.flush() 144 failed = True 145 return failed 146 147 148def dash_R_cleanup(fs, ps, pic, zdc, abcs): 149 import copyreg 150 import collections.abc 151 152 # Restore some original values. 153 warnings.filters[:] = fs 154 copyreg.dispatch_table.clear() 155 copyreg.dispatch_table.update(ps) 156 sys.path_importer_cache.clear() 157 sys.path_importer_cache.update(pic) 158 try: 159 import zipimport 160 except ImportError: 161 pass # Run unmodified on platforms without zipimport support 162 else: 163 zipimport._zip_directory_cache.clear() 164 zipimport._zip_directory_cache.update(zdc) 165 166 # clear type cache 167 sys._clear_type_cache() 168 169 # Clear ABC registries, restoring previously saved ABC registries. 170 abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] 171 abs_classes = filter(isabstract, abs_classes) 172 for abc in abs_classes: 173 for obj in abc.__subclasses__() + [abc]: 174 for ref in abcs.get(obj, set()): 175 if ref() is not None: 176 obj.register(ref()) 177 obj._abc_caches_clear() 178 179 clear_caches() 180 181 182def clear_caches(): 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 188 # 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. 195 # Don't worry about resetting the cache if the module is not loaded 196 try: 197 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: 263 pass 264 else: 265 ctypes._reset_cache() 266 267 try: 268 typing = sys.modules['typing'] 269 except KeyError: 270 pass 271 else: 272 for f in typing._cleanups: 273 f() 274 275 support.gc_collect() 276 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 284 [chr(i) for i in range(256)] 285 # int cache 286 list(range(-5, 257)) 287