[Python-checkins] bpo-31009: Fix support.fd_count() on Windows (#2862)

Victor Stinner webhook-mailer at python.org
Tue Jul 25 11:45:58 EDT 2017


https://github.com/python/cpython/commit/302bbbe9ba5c72559913e2ea006c921f698a729d
commit: 302bbbe9ba5c72559913e2ea006c921f698a729d
branch: master
author: Victor Stinner <victor.stinner at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-07-25T17:45:53+02:00
summary:

bpo-31009: Fix support.fd_count() on Windows (#2862)

* bpo-31009: Fix support.fd_count() on Windows

On Windows, test.support.fd_count() now calls
msvcrt.CrtSetReportMode() to not kill the process nor log any error
on stderr on os.dup(fd) if the file descriptor is invalid.

* Fix for release mode

files:
M Lib/test/support/__init__.py
M Lib/test/test_regrtest.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 3a4d27e6b88..7a4671c1b2b 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2649,12 +2649,6 @@ def disable_faulthandler():
             faulthandler.enable(file=fd, all_threads=True)
 
 
-try:
-    MAXFD = os.sysconf("SC_OPEN_MAX")
-except Exception:
-    MAXFD = 256
-
-
 def fd_count():
     """Count the number of open file descriptors.
     """
@@ -2665,16 +2659,48 @@ def fd_count():
         except FileNotFoundError:
             pass
 
-    count = 0
-    for fd in range(MAXFD):
+    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:
-            # 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
+            import msvcrt
+            msvcrt.CrtSetReportMode
+        except (AttributeError, ImportError):
+            # no msvcrt or a release build
+            pass
         else:
-            os.close(fd2)
-            count += 1
+            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
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index f63ed647f80..b756839748a 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -835,22 +835,10 @@ def test_huntrleaks_fd_leak(self):
             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')
 



More information about the Python-checkins mailing list