From f6e58aefde2e57e4cb11ea7743955da53a3f1e80 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 10 Jun 2020 18:49:23 +0200 Subject: [PATCH] bpo-40826: Fix test_repl.test_close_stdin() on Windows (GH-20779) 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. * Add msvcrt.GetErrorMode(). * SuppressCrashReport now uses GetErrorMode() and SetErrorMode() of the msvcrt module, rather than using ctypes. * Remove also an unused variable (deadline) in wait_process(). --- Lib/test/audit-tests.py | 4 +-- Lib/test/libregrtest/setup.py | 27 +----------------- Lib/test/support/__init__.py | 53 ++++++++++++++++++++++------------- Lib/test/test_repl.py | 6 +++- PC/clinic/msvcrtmodule.c.h | 20 ++++++++++++- PC/msvcrtmodule.c | 20 +++++++++++++ 6 files changed, 81 insertions(+), 49 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index b90c4b8f757..a58395b068b 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -350,9 +350,9 @@ def test_socket(): 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 ce8149677e0..1f264c1be49 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 setup_tests(ns): 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 3a5f7b556d7..83b21733de0 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1899,6 +1899,27 @@ def check__all__(test_case, module, name_of_module=None, extra=(), 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. @@ -1910,30 +1931,25 @@ 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. """ if sys.platform.startswith('win'): # 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.GetErrorMode() + + 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, @@ -1985,10 +2001,10 @@ class SuppressCrashReport: 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) @@ -2332,7 +2348,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 563f188706b..03bf8d8b548 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -98,7 +98,11 @@ class TestInteractiveInterpreter(unittest.TestCase): 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) diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index 9701e8a63be..1ac82cb965b 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -590,6 +590,24 @@ exit: #endif /* defined(_DEBUG) */ +PyDoc_STRVAR(msvcrt_GetErrorMode__doc__, +"GetErrorMode($module, /)\n" +"--\n" +"\n" +"Wrapper around GetErrorMode."); + +#define MSVCRT_GETERRORMODE_METHODDEF \ + {"GetErrorMode", (PyCFunction)msvcrt_GetErrorMode, METH_NOARGS, msvcrt_GetErrorMode__doc__}, + +static PyObject * +msvcrt_GetErrorMode_impl(PyObject *module); + +static PyObject * +msvcrt_GetErrorMode(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return msvcrt_GetErrorMode_impl(module); +} + PyDoc_STRVAR(msvcrt_SetErrorMode__doc__, "SetErrorMode($module, mode, /)\n" "--\n" @@ -629,4 +647,4 @@ exit: #ifndef MSVCRT_SET_ERROR_MODE_METHODDEF #define MSVCRT_SET_ERROR_MODE_METHODDEF #endif /* !defined(MSVCRT_SET_ERROR_MODE_METHODDEF) */ -/*[clinic end generated code: output=ab3b5ce5c1447f0e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=20dfbc768edce7c0 input=a9049054013a1b77]*/ diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index faceb03fba3..b7ff20ab0fb 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -482,6 +482,25 @@ msvcrt_set_error_mode_impl(PyObject *module, int mode) } #endif /* _DEBUG */ +/*[clinic input] +msvcrt.GetErrorMode + +Wrapper around GetErrorMode. +[clinic start generated code]*/ + +static PyObject * +msvcrt_GetErrorMode_impl(PyObject *module) +/*[clinic end generated code: output=3103fc6145913591 input=5a7fb083b6dd71fd]*/ +{ + unsigned int res; + + _Py_BEGIN_SUPPRESS_IPH + res = GetErrorMode(); + _Py_END_SUPPRESS_IPH + + return PyLong_FromUnsignedLong(res); +} + /*[clinic input] msvcrt.SetErrorMode @@ -520,6 +539,7 @@ static struct PyMethodDef msvcrt_functions[] = { MSVCRT_GETCHE_METHODDEF MSVCRT_PUTCH_METHODDEF MSVCRT_UNGETCH_METHODDEF + MSVCRT_GETERRORMODE_METHODDEF MSVCRT_SETERRORMODE_METHODDEF MSVCRT_CRTSETREPORTFILE_METHODDEF MSVCRT_CRTSETREPORTMODE_METHODDEF