From 99ba73d1188f4d52d2c741c26267da00a008f379 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Jun 2018 13:47:24 +0200 Subject: [PATCH] bpo-31009: Move fd_count() to test.support (#7308) * Move fd_count() from test.libregrtest.refleak to test.support * Fix support.fd_count() on Windows: Call CrtSetReportMode() to not kill the process on invalid file descriptor if Python is compiled in debug mode. --- Lib/test/libregrtest/refleak.py | 26 +-------------- Lib/test/support/__init__.py | 59 ++++++++++++++++++++++++++++++++- Lib/test/test_regrtest.py | 14 +------- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 0bd8288e27..bf0ad81f96 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -13,30 +13,6 @@ except Exception: MAXFD = 256 -def fd_count(): - """Count the number of open file descriptors""" - if sys.platform.startswith(('linux', 'freebsd')): - try: - names = os.listdir("/proc/self/fd") - return len(names) - except FileNotFoundError: - pass - - count = 0 - for fd in range(MAXFD): - try: - # Prefer dup() over fstat(). fstat() can require input/output - # whereas dup() doesn't. - fd2 = os.dup(fd) - except OSError as e: - if e.errno != errno.EBADF: - raise - else: - os.close(fd2) - count += 1 - return count - - def dash_R(the_module, test, indirect_test, huntrleaks): """Run a test multiple times, looking for reference leaks. @@ -182,7 +158,7 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): func1 = sys.getallocatedblocks func2 = sys.gettotalrefcount gc.collect() - return func1(), func2(), fd_count() + return func1(), func2(), support.fd_count() def clear_caches(): diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index e46394e89d..3def27b12e 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -107,7 +107,7 @@ __all__ = [ "check_warnings", "check_no_resource_warning", "EnvironmentVarGuard", "run_with_locale", "swap_item", "swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict", - "run_with_tz", "PGO", "missing_compiler_executable", + "run_with_tz", "PGO", "missing_compiler_executable", "fd_count", ] class Error(Exception): @@ -2691,6 +2691,63 @@ def disable_faulthandler(): faulthandler.enable(file=fd, all_threads=True) +def fd_count(): + """Count the number of open file descriptors. + """ + if sys.platform.startswith(('linux', 'freebsd')): + try: + names = os.listdir("/proc/self/fd") + return len(names) + except FileNotFoundError: + pass + + old_modes = None + if sys.platform == 'win32': + # bpo-25306, bpo-31009: Call CrtSetReportMode() to not kill the process + # on invalid file descriptor if Python is compiled in debug mode + try: + import msvcrt + msvcrt.CrtSetReportMode + except (AttributeError, ImportError): + # no msvcrt or a release build + pass + else: + old_modes = {} + for report_type in (msvcrt.CRT_WARN, + msvcrt.CRT_ERROR, + msvcrt.CRT_ASSERT): + old_modes[report_type] = msvcrt.CrtSetReportMode(report_type, 0) + + MAXFD = 256 + if hasattr(os, 'sysconf'): + try: + MAXFD = os.sysconf("SC_OPEN_MAX") + except OSError: + pass + + try: + count = 0 + for fd in range(MAXFD): + try: + # Prefer dup() over fstat(). fstat() can require input/output + # whereas dup() doesn't. + fd2 = os.dup(fd) + except OSError as e: + if e.errno != errno.EBADF: + raise + else: + os.close(fd2) + count += 1 + finally: + if old_modes is not None: + for report_type in (msvcrt.CRT_WARN, + msvcrt.CRT_ERROR, + msvcrt.CRT_ASSERT): + msvcrt.CrtSetReportMode(report_type, old_modes[report_type]) + + return count + + class SaveSignals: """ Save an restore signal handlers. diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index f63ed647f8..b756839748 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -835,22 +835,10 @@ class ArgsTestCase(BaseTestCase): import os import unittest - # Issue #25306: Disable popups and logs to stderr on assertion - # failures in MSCRT - try: - import msvcrt - msvcrt.CrtSetReportMode - except (ImportError, AttributeError): - # no Windows, o release build - pass - else: - for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: - msvcrt.CrtSetReportMode(m, 0) - class FDLeakTest(unittest.TestCase): def test_leak(self): fd = os.open(__file__, os.O_RDONLY) - # bug: never cloes the file descriptor + # bug: never close the file descriptor """) self.check_leak(code, 'file descriptors') -- 2.50.1