Skip to content

Commit 99ba73d

Browse files
authored
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.
1 parent 1d5198f commit 99ba73d

File tree

3 files changed

+60
-39
lines changed

3 files changed

+60
-39
lines changed

Lib/test/libregrtest/refleak.py

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,6 @@
1313
MAXFD = 256
1414

1515

16-
def fd_count():
17-
"""Count the number of open file descriptors"""
18-
if sys.platform.startswith(('linux', 'freebsd')):
19-
try:
20-
names = os.listdir("/proc/self/fd")
21-
return len(names)
22-
except FileNotFoundError:
23-
pass
24-
25-
count = 0
26-
for fd in range(MAXFD):
27-
try:
28-
# Prefer dup() over fstat(). fstat() can require input/output
29-
# whereas dup() doesn't.
30-
fd2 = os.dup(fd)
31-
except OSError as e:
32-
if e.errno != errno.EBADF:
33-
raise
34-
else:
35-
os.close(fd2)
36-
count += 1
37-
return count
38-
39-
4016
def dash_R(the_module, test, indirect_test, huntrleaks):
4117
"""Run a test multiple times, looking for reference leaks.
4218
@@ -182,7 +158,7 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
182158
func1 = sys.getallocatedblocks
183159
func2 = sys.gettotalrefcount
184160
gc.collect()
185-
return func1(), func2(), fd_count()
161+
return func1(), func2(), support.fd_count()
186162

187163

188164
def clear_caches():

Lib/test/support/__init__.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
"check_warnings", "check_no_resource_warning", "EnvironmentVarGuard",
108108
"run_with_locale", "swap_item",
109109
"swap_attr", "Matcher", "set_memlimit", "SuppressCrashReport", "sortdict",
110-
"run_with_tz", "PGO", "missing_compiler_executable",
110+
"run_with_tz", "PGO", "missing_compiler_executable", "fd_count",
111111
]
112112

113113
class Error(Exception):
@@ -2691,6 +2691,63 @@ def disable_faulthandler():
26912691
faulthandler.enable(file=fd, all_threads=True)
26922692

26932693

2694+
def fd_count():
2695+
"""Count the number of open file descriptors.
2696+
"""
2697+
if sys.platform.startswith(('linux', 'freebsd')):
2698+
try:
2699+
names = os.listdir("/proc/self/fd")
2700+
return len(names)
2701+
except FileNotFoundError:
2702+
pass
2703+
2704+
old_modes = None
2705+
if sys.platform == 'win32':
2706+
# bpo-25306, bpo-31009: Call CrtSetReportMode() to not kill the process
2707+
# on invalid file descriptor if Python is compiled in debug mode
2708+
try:
2709+
import msvcrt
2710+
msvcrt.CrtSetReportMode
2711+
except (AttributeError, ImportError):
2712+
# no msvcrt or a release build
2713+
pass
2714+
else:
2715+
old_modes = {}
2716+
for report_type in (msvcrt.CRT_WARN,
2717+
msvcrt.CRT_ERROR,
2718+
msvcrt.CRT_ASSERT):
2719+
old_modes[report_type] = msvcrt.CrtSetReportMode(report_type, 0)
2720+
2721+
MAXFD = 256
2722+
if hasattr(os, 'sysconf'):
2723+
try:
2724+
MAXFD = os.sysconf("SC_OPEN_MAX")
2725+
except OSError:
2726+
pass
2727+
2728+
try:
2729+
count = 0
2730+
for fd in range(MAXFD):
2731+
try:
2732+
# Prefer dup() over fstat(). fstat() can require input/output
2733+
# whereas dup() doesn't.
2734+
fd2 = os.dup(fd)
2735+
except OSError as e:
2736+
if e.errno != errno.EBADF:
2737+
raise
2738+
else:
2739+
os.close(fd2)
2740+
count += 1
2741+
finally:
2742+
if old_modes is not None:
2743+
for report_type in (msvcrt.CRT_WARN,
2744+
msvcrt.CRT_ERROR,
2745+
msvcrt.CRT_ASSERT):
2746+
msvcrt.CrtSetReportMode(report_type, old_modes[report_type])
2747+
2748+
return count
2749+
2750+
26942751
class SaveSignals:
26952752
"""
26962753
Save an restore signal handlers.

Lib/test/test_regrtest.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -835,22 +835,10 @@ def test_huntrleaks_fd_leak(self):
835835
import os
836836
import unittest
837837
838-
# Issue #25306: Disable popups and logs to stderr on assertion
839-
# failures in MSCRT
840-
try:
841-
import msvcrt
842-
msvcrt.CrtSetReportMode
843-
except (ImportError, AttributeError):
844-
# no Windows, o release build
845-
pass
846-
else:
847-
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
848-
msvcrt.CrtSetReportMode(m, 0)
849-
850838
class FDLeakTest(unittest.TestCase):
851839
def test_leak(self):
852840
fd = os.open(__file__, os.O_RDONLY)
853-
# bug: never cloes the file descriptor
841+
# bug: never close the file descriptor
854842
""")
855843
self.check_leak(code, 'file descriptors')
856844

0 commit comments

Comments
 (0)