From 4a4f660cfde8b683634c53e6214a6baa51de43b1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jun 2020 19:24:56 +0200 Subject: [PATCH] bpo-40826: Fix test_repl.test_close_stdin() on Windows (GH-20779) (GH-20785) test_repl.test_close_stdin() now calls support.suppress_msvcrt_asserts() to fix the test on Windows. * Move suppress_msvcrt_asserts() from test.libregrtest.setup to test.support. Make its verbose parameter optional: verbose=False by default. * SuppressCrashReport now uses SetErrorMode() of the msvcrt module, rather than using ctypes. * Remove also an unused variable (deadline) in wait_process(). (cherry picked from commit f6e58aefde2e57e4cb11ea7743955da53a3f1e80) --- Lib/test/audit-tests.py | 4 +-- Lib/test/libregrtest/setup.py | 27 +------------------ Lib/test/support/__init__.py | 51 +++++++++++++++++++++++------------ Lib/test/test_repl.py | 6 ++++- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index b90c4b8f75794d..a58395b068b395 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -350,9 +350,9 @@ def hook(event, args): if __name__ == "__main__": - from test.libregrtest.setup import suppress_msvcrt_asserts + from test.support import suppress_msvcrt_asserts - suppress_msvcrt_asserts(False) + suppress_msvcrt_asserts() test = sys.argv[1] globals()[test]() diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index ce8149677e0b97..1f264c1be49fe0 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -69,7 +69,7 @@ def setup_tests(ns): if ns.threshold is not None: gc.set_threshold(ns.threshold) - suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2) + support.suppress_msvcrt_asserts(ns.verbose and ns.verbose >= 2) support.use_resources = ns.use_resources @@ -93,31 +93,6 @@ def _test_audit_hook(name, args): support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout) -def suppress_msvcrt_asserts(verbose): - try: - import msvcrt - except ImportError: - return - - msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS| - msvcrt.SEM_NOALIGNMENTFAULTEXCEPT| - msvcrt.SEM_NOGPFAULTERRORBOX| - msvcrt.SEM_NOOPENFILEERRORBOX) - try: - msvcrt.CrtSetReportMode - except AttributeError: - # release build - return - - for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: - if verbose: - msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) - msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) - else: - msvcrt.CrtSetReportMode(m, 0) - - - def replace_stdout(): """Set stdout encoder error handler to backslashreplace (as stderr error handler) to avoid UnicodeEncodeError when printing a traceback""" diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 8dee5b9dcc7ab9..f8670149a2e0e2 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2532,6 +2532,27 @@ def test__all__(self): test_case.assertCountEqual(module.__all__, expected) +def suppress_msvcrt_asserts(verbose=False): + try: + import msvcrt + except ImportError: + return + + msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS + | msvcrt.SEM_NOALIGNMENTFAULTEXCEPT + | msvcrt.SEM_NOGPFAULTERRORBOX + | msvcrt.SEM_NOOPENFILEERRORBOX) + + # CrtSetReportMode() is only available in debug build + if hasattr(msvcrt, 'CrtSetReportMode'): + for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: + if verbose: + msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) + msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) + else: + msvcrt.CrtSetReportMode(m, 0) + + class SuppressCrashReport: """Try to prevent a crash report from popping up. @@ -2543,7 +2564,7 @@ class SuppressCrashReport: def __enter__(self): """On Windows, disable Windows Error Reporting dialogs using - SetErrorMode. + SetErrorMode() and CrtSetReportMode(). On UNIX, try to save the previous core file size limit, then set soft limit to 0. @@ -2552,21 +2573,18 @@ def __enter__(self): # see http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx # GetErrorMode is not available on Windows XP and Windows Server 2003, # but SetErrorMode returns the previous value, so we can use that - import ctypes - self._k32 = ctypes.windll.kernel32 - SEM_NOGPFAULTERRORBOX = 0x02 - self.old_value = self._k32.SetErrorMode(SEM_NOGPFAULTERRORBOX) - self._k32.SetErrorMode(self.old_value | SEM_NOGPFAULTERRORBOX) - - # Suppress assert dialogs in debug builds - # (see http://bugs.python.org/issue23314) try: import msvcrt - msvcrt.CrtSetReportMode - except (AttributeError, ImportError): - # no msvcrt or a release build - pass - else: + except ImportError: + return + + self.old_value = msvcrt.SetErrorMode(msvcrt.SEM_NOGPFAULTERRORBOX) + + msvcrt.SetErrorMode(self.old_value | msvcrt.SEM_NOGPFAULTERRORBOX) + + # bpo-23314: Suppress assert dialogs in debug builds. + # CrtSetReportMode() is only available in debug build. + if hasattr(msvcrt, 'CrtSetReportMode'): self.old_modes = {} for report_type in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, @@ -2617,10 +2635,10 @@ def __exit__(self, *ignore_exc): return if sys.platform.startswith('win'): - self._k32.SetErrorMode(self.old_value) + import msvcrt + msvcrt.SetErrorMode(self.old_value) if self.old_modes: - import msvcrt for report_type, (old_mode, old_file) in self.old_modes.items(): msvcrt.CrtSetReportMode(report_type, old_mode) msvcrt.CrtSetReportFile(report_type, old_file) @@ -3097,7 +3115,6 @@ def wait_process(pid, *, exitcode, timeout=None): if timeout is None: timeout = SHORT_TIMEOUT t0 = time.monotonic() - deadline = t0 + timeout sleep = 0.001 max_sleep = 0.1 while True: diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 563f188706b93f..03bf8d8b5483fb 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -98,7 +98,11 @@ def test_close_stdin(self): print("before close") os.close(0) ''') - process = spawn_repl() + prepare_repl = dedent(''' + from test.support import suppress_msvcrt_asserts + suppress_msvcrt_asserts() + ''') + process = spawn_repl('-c', prepare_repl) output = process.communicate(user_input)[0] self.assertEqual(process.returncode, 0) self.assertIn('before close', output)