Commit 95a91df0 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-30764: Windows support.SuppressCrashReport (#2423)

* Add Windows support to test.support.SuppressCrashReport: call
  SetErrorMode() and CrtSetReportMode().
* _testcapi: add CrtSetReportMode() and CrtSetReportFile() functions
  and CRT_xxx and CRTDBG_xxx constants needed by SuppressCrashReport.
parent 305f333a
...@@ -1863,8 +1863,34 @@ class SuppressCrashReport: ...@@ -1863,8 +1863,34 @@ class SuppressCrashReport:
soft limit to 0. soft limit to 0.
""" """
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
# TODO: backport the Windows implementation # 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 _testcapi
_testcapi.CrtSetReportMode
except (AttributeError, ImportError):
# no _testcapi or a release build
pass pass
else:
self.old_modes = {}
for report_type in [_testcapi.CRT_WARN,
_testcapi.CRT_ERROR,
_testcapi.CRT_ASSERT]:
old_mode = _testcapi.CrtSetReportMode(report_type,
_testcapi.CRTDBG_MODE_FILE)
old_file = _testcapi.CrtSetReportFile(report_type,
_testcapi.CRTDBG_FILE_STDERR)
self.old_modes[report_type] = old_mode, old_file
else: else:
try: try:
import resource import resource
...@@ -1906,15 +1932,15 @@ class SuppressCrashReport: ...@@ -1906,15 +1932,15 @@ class SuppressCrashReport:
return return
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
# TODO: backport the Windows implementation self._k32.SetErrorMode(self.old_value)
pass
if self.old_modes:
import _testcapi
for report_type, (old_mode, old_file) in self.old_modes.items():
_testcapi.CrtSetReportMode(report_type, old_mode)
_testcapi.CrtSetReportFile(report_type, old_file)
else: else:
try:
import resource import resource
except ImportError:
resource = None
if resource is not None:
try: try:
resource.setrlimit(resource.RLIMIT_CORE, self.old_value) resource.setrlimit(resource.RLIMIT_CORE, self.old_value)
except (ValueError, OSError): except (ValueError, OSError):
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#include "datetime.h" #include "datetime.h"
#include "marshal.h" #include "marshal.h"
#include <signal.h> #include <signal.h>
#ifdef MS_WINDOWS
# include <crtdbg.h>
#endif
#ifdef WITH_THREAD #ifdef WITH_THREAD
#include "pythread.h" #include "pythread.h"
...@@ -2501,6 +2504,42 @@ test_raise_signal(PyObject* self, PyObject *args) ...@@ -2501,6 +2504,42 @@ test_raise_signal(PyObject* self, PyObject *args)
} }
#ifdef MS_WINDOWS
static PyObject*
msvcrt_CrtSetReportMode(PyObject* self, PyObject *args)
{
int type, mode;
int res;
if (!PyArg_ParseTuple(args, "ii:CrtSetReportMode", &type, &mode)) {
return NULL;
}
res = _CrtSetReportMode(type, mode);
if (res == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return PyInt_FromLong(res);
}
static PyObject*
msvcrt_CrtSetReportFile(PyObject* self, PyObject *args)
{
int type, file;
long res;
if (!PyArg_ParseTuple(args, "ii:CrtSetReportFile", &type, &file)) {
return NULL;
}
res = (long)_CrtSetReportFile(type, (_HFILE)file);
return PyInt_FromLong(res);
}
#endif
static PyMethodDef TestMethods[] = { static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS},
{"set_errno", set_errno, METH_VARARGS}, {"set_errno", set_errno, METH_VARARGS},
...@@ -2613,6 +2652,10 @@ static PyMethodDef TestMethods[] = { ...@@ -2613,6 +2652,10 @@ static PyMethodDef TestMethods[] = {
{"pymarshal_read_object_from_file", {"pymarshal_read_object_from_file",
pymarshal_read_object_from_file, METH_VARARGS}, pymarshal_read_object_from_file, METH_VARARGS},
{"raise_signal", (PyCFunction)test_raise_signal, METH_VARARGS}, {"raise_signal", (PyCFunction)test_raise_signal, METH_VARARGS},
#ifdef MS_WINDOWS
{"CrtSetReportMode", (PyCFunction)msvcrt_CrtSetReportMode, METH_VARARGS},
{"CrtSetReportFile", (PyCFunction)msvcrt_CrtSetReportFile, METH_VARARGS},
#endif
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -2809,6 +2852,14 @@ init_testcapi(void) ...@@ -2809,6 +2852,14 @@ init_testcapi(void)
PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyInt_FromSsize_t(PY_SSIZE_T_MIN)); PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyInt_FromSsize_t(PY_SSIZE_T_MIN));
PyModule_AddObject(m, "SIZEOF_PYGC_HEAD", PyInt_FromSsize_t(sizeof(PyGC_Head))); PyModule_AddObject(m, "SIZEOF_PYGC_HEAD", PyInt_FromSsize_t(sizeof(PyGC_Head)));
#ifdef MS_WINDOWS
PyModule_AddIntConstant(m, "CRT_WARN", _CRT_WARN);
PyModule_AddIntConstant(m, "CRT_ERROR", _CRT_ERROR);
PyModule_AddIntConstant(m, "CRT_ASSERT", _CRT_ASSERT);
PyModule_AddIntConstant(m, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
PyModule_AddIntConstant(m, "CRTDBG_FILE_STDERR", (int)_CRTDBG_FILE_STDERR);
#endif
TestError = PyErr_NewException("_testcapi.error", NULL, NULL); TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
Py_INCREF(TestError); Py_INCREF(TestError);
PyModule_AddObject(m, "error", TestError); PyModule_AddObject(m, "error", TestError);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment