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().
This commit is contained in:
Victor Stinner 2020-06-10 18:49:23 +02:00 committed by GitHub
parent d36cf5f1d2
commit f6e58aefde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 49 deletions

View File

@ -350,9 +350,9 @@ def test_socket():
if __name__ == "__main__": 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] test = sys.argv[1]
globals()[test]() globals()[test]()

View File

@ -69,7 +69,7 @@ def setup_tests(ns):
if ns.threshold is not None: if ns.threshold is not None:
gc.set_threshold(ns.threshold) 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 support.use_resources = ns.use_resources
@ -93,31 +93,6 @@ def setup_tests(ns):
support.LONG_TIMEOUT = min(support.LONG_TIMEOUT, ns.timeout) 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(): def replace_stdout():
"""Set stdout encoder error handler to backslashreplace (as stderr error """Set stdout encoder error handler to backslashreplace (as stderr error
handler) to avoid UnicodeEncodeError when printing a traceback""" handler) to avoid UnicodeEncodeError when printing a traceback"""

View File

@ -1899,6 +1899,27 @@ def check__all__(test_case, module, name_of_module=None, extra=(),
test_case.assertCountEqual(module.__all__, expected) 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: class SuppressCrashReport:
"""Try to prevent a crash report from popping up. """Try to prevent a crash report from popping up.
@ -1910,30 +1931,25 @@ class SuppressCrashReport:
def __enter__(self): def __enter__(self):
"""On Windows, disable Windows Error Reporting dialogs using """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 On UNIX, try to save the previous core file size limit, then set
soft limit to 0. soft limit to 0.
""" """
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
# see http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621.aspx # 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: try:
import msvcrt import msvcrt
msvcrt.CrtSetReportMode except ImportError:
except (AttributeError, ImportError): return
# no msvcrt or a release build
pass self.old_value = msvcrt.GetErrorMode()
else:
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 = {} self.old_modes = {}
for report_type in [msvcrt.CRT_WARN, for report_type in [msvcrt.CRT_WARN,
msvcrt.CRT_ERROR, msvcrt.CRT_ERROR,
@ -1985,10 +2001,10 @@ class SuppressCrashReport:
return return
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
self._k32.SetErrorMode(self.old_value) import msvcrt
msvcrt.SetErrorMode(self.old_value)
if self.old_modes: if self.old_modes:
import msvcrt
for report_type, (old_mode, old_file) in self.old_modes.items(): for report_type, (old_mode, old_file) in self.old_modes.items():
msvcrt.CrtSetReportMode(report_type, old_mode) msvcrt.CrtSetReportMode(report_type, old_mode)
msvcrt.CrtSetReportFile(report_type, old_file) msvcrt.CrtSetReportFile(report_type, old_file)
@ -2332,7 +2348,6 @@ def wait_process(pid, *, exitcode, timeout=None):
if timeout is None: if timeout is None:
timeout = SHORT_TIMEOUT timeout = SHORT_TIMEOUT
t0 = time.monotonic() t0 = time.monotonic()
deadline = t0 + timeout
sleep = 0.001 sleep = 0.001
max_sleep = 0.1 max_sleep = 0.1
while True: while True:

View File

@ -98,7 +98,11 @@ class TestInteractiveInterpreter(unittest.TestCase):
print("before close") print("before close")
os.close(0) 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] output = process.communicate(user_input)[0]
self.assertEqual(process.returncode, 0) self.assertEqual(process.returncode, 0)
self.assertIn('before close', output) self.assertIn('before close', output)

View File

@ -590,6 +590,24 @@ exit:
#endif /* defined(_DEBUG) */ #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__, PyDoc_STRVAR(msvcrt_SetErrorMode__doc__,
"SetErrorMode($module, mode, /)\n" "SetErrorMode($module, mode, /)\n"
"--\n" "--\n"
@ -629,4 +647,4 @@ exit:
#ifndef MSVCRT_SET_ERROR_MODE_METHODDEF #ifndef MSVCRT_SET_ERROR_MODE_METHODDEF
#define MSVCRT_SET_ERROR_MODE_METHODDEF #define MSVCRT_SET_ERROR_MODE_METHODDEF
#endif /* !defined(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]*/

View File

@ -482,6 +482,25 @@ msvcrt_set_error_mode_impl(PyObject *module, int mode)
} }
#endif /* _DEBUG */ #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] /*[clinic input]
msvcrt.SetErrorMode msvcrt.SetErrorMode
@ -520,6 +539,7 @@ static struct PyMethodDef msvcrt_functions[] = {
MSVCRT_GETCHE_METHODDEF MSVCRT_GETCHE_METHODDEF
MSVCRT_PUTCH_METHODDEF MSVCRT_PUTCH_METHODDEF
MSVCRT_UNGETCH_METHODDEF MSVCRT_UNGETCH_METHODDEF
MSVCRT_GETERRORMODE_METHODDEF
MSVCRT_SETERRORMODE_METHODDEF MSVCRT_SETERRORMODE_METHODDEF
MSVCRT_CRTSETREPORTFILE_METHODDEF MSVCRT_CRTSETREPORTFILE_METHODDEF
MSVCRT_CRTSETREPORTMODE_METHODDEF MSVCRT_CRTSETREPORTMODE_METHODDEF