|
6 | 6 | c_char, c_wchar, c_byte, c_char_p, c_wchar_p, |
7 | 7 | c_short, c_int, c_long, c_longlong, c_void_p, |
8 | 8 | c_float, c_double, c_longdouble) |
9 | | -from test.support import import_helper |
| 9 | +from test.support import import_helper, refcount_test |
10 | 10 | _ctypes_test = import_helper.import_module("_ctypes_test") |
11 | 11 | from _ctypes import _Pointer, _SimpleCData |
| 12 | +import gc |
12 | 13 |
|
13 | 14 |
|
14 | 15 | try: |
@@ -479,18 +480,28 @@ def original(): |
479 | 480 | self.assertEqual(original(), "original") |
480 | 481 | self.assertEqual(original(), "replacement") |
481 | 482 |
|
| 483 | + @refcount_test |
482 | 484 | def test_function_code_object_memory_leak(self): |
483 | | - def get_function(i): |
| 485 | + def get_code(i): |
484 | 486 | ns = {} |
485 | 487 | exec(f"def f(): return {i}", ns) |
486 | | - return ns["f"] |
| 488 | + return ns["f"].__code__ |
487 | 489 |
|
488 | | - def f(): pass |
| 490 | + codes = [get_code(i) for i in range(100)] |
| 491 | + refcounts = [sys.getrefcount(code) for code in codes] |
489 | 492 |
|
490 | | - for i in range(1000): |
491 | | - f.__code__ = get_function(i).__code__ |
| 493 | + def f(): |
| 494 | + pass |
492 | 495 |
|
493 | | - self.assertEqual(f(), 999) |
| 496 | + for i, code in enumerate(codes): |
| 497 | + f.__code__ = code |
| 498 | + self.assertEqual(f(), i) |
| 499 | + |
| 500 | + del f |
| 501 | + gc.collect() |
| 502 | + |
| 503 | + for code, refcount in zip(codes, refcounts): |
| 504 | + self.assertEqual(sys.getrefcount(code), refcount) |
494 | 505 |
|
495 | 506 |
|
496 | 507 | if __name__ == '__main__': |
|
0 commit comments