summaryrefslogtreecommitdiffstats
path: root/Modules/faulthandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/faulthandler.c')
-rw-r--r--Modules/faulthandler.c131
1 files changed, 77 insertions, 54 deletions
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index c729414..9c763ab 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -5,7 +5,13 @@
#include <frameobject.h>
#include <signal.h>
#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
-#include <pthread.h>
+# include <pthread.h>
+#endif
+#ifdef MS_WINDOWS
+# include <windows.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
#endif
/* Allocate at maximum 100 MB of the stack to raise the stack overflow */
@@ -127,32 +133,46 @@ static stack_t stack;
call its flush() method.
If file is NULL or Py_None, use sys.stderr as the new file.
+ If file is an integer, it will be treated as file descriptor.
- On success, return the new file and write the file descriptor into *p_fd.
- On error, return NULL. */
+ On success, return the file descriptor and write the new file into *file_ptr.
+ On error, return -1. */
-static PyObject*
-faulthandler_get_fileno(PyObject *file, int *p_fd)
+static int
+faulthandler_get_fileno(PyObject **file_ptr)
{
PyObject *result;
long fd_long;
int fd;
+ PyObject *file = *file_ptr;
if (file == NULL || file == Py_None) {
file = _PySys_GetObjectId(&PyId_stderr);
if (file == NULL) {
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
- return NULL;
+ return -1;
}
if (file == Py_None) {
PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None");
- return NULL;
+ return -1;
}
}
+ else if (PyLong_Check(file)) {
+ fd = _PyLong_AsInt(file);
+ if (fd == -1 && PyErr_Occurred())
+ return -1;
+ if (fd < 0 || !_PyVerify_fd(fd)) {
+ PyErr_SetString(PyExc_ValueError,
+ "file is not a valid file descripter");
+ return -1;
+ }
+ *file_ptr = NULL;
+ return fd;
+ }
result = _PyObject_CallMethodId(file, &PyId_fileno, "");
if (result == NULL)
- return NULL;
+ return -1;
fd = -1;
if (PyLong_Check(result)) {
@@ -165,7 +185,7 @@ faulthandler_get_fileno(PyObject *file, int *p_fd)
if (fd == -1) {
PyErr_SetString(PyExc_RuntimeError,
"file.fileno() is not a valid file descriptor");
- return NULL;
+ return -1;
}
result = _PyObject_CallMethodId(file, &PyId_flush, "");
@@ -175,8 +195,8 @@ faulthandler_get_fileno(PyObject *file, int *p_fd)
/* ignore flush() error */
PyErr_Clear();
}
- *p_fd = fd;
- return file;
+ *file_ptr = file;
+ return fd;
}
/* Get the state of the current thread: only call this function if the current
@@ -209,8 +229,8 @@ faulthandler_dump_traceback_py(PyObject *self,
&file, &all_threads))
return NULL;
- file = faulthandler_get_fileno(file, &fd);
- if (file == NULL)
+ fd = faulthandler_get_fileno(&file);
+ if (fd < 0)
return NULL;
tstate = get_thread_state();
@@ -333,8 +353,8 @@ faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs)
"|Oi:enable", kwlist, &file, &all_threads))
return NULL;
- file = faulthandler_get_fileno(file, &fd);
- if (file == NULL)
+ fd = faulthandler_get_fileno(&file);
+ if (fd < 0)
return NULL;
tstate = get_thread_state();
@@ -342,7 +362,7 @@ faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL;
Py_XDECREF(fatal_error.file);
- Py_INCREF(file);
+ Py_XINCREF(file);
fatal_error.file = file;
fatal_error.fd = fd;
fatal_error.all_threads = all_threads;
@@ -452,7 +472,7 @@ faulthandler_thread(void *unused)
assert(st == PY_LOCK_FAILURE);
/* get the thread holding the GIL, NULL if no thread hold the GIL */
- current = _Py_atomic_load_relaxed(&_PyThreadState_Current);
+ current = (PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current);
write(thread.fd, thread.header, (int)thread.header_len);
@@ -547,8 +567,8 @@ faulthandler_dump_traceback_later(PyObject *self,
if (tstate == NULL)
return NULL;
- file = faulthandler_get_fileno(file, &fd);
- if (file == NULL)
+ fd = faulthandler_get_fileno(&file);
+ if (fd < 0)
return NULL;
/* format the timeout */
@@ -561,7 +581,7 @@ faulthandler_dump_traceback_later(PyObject *self,
cancel_dump_traceback_later();
Py_XDECREF(thread.file);
- Py_INCREF(file);
+ Py_XINCREF(file);
thread.file = file;
thread.fd = fd;
thread.timeout_us = timeout_us;
@@ -731,8 +751,8 @@ faulthandler_register_py(PyObject *self,
if (tstate == NULL)
return NULL;
- file = faulthandler_get_fileno(file, &fd);
- if (file == NULL)
+ fd = faulthandler_get_fileno(&file);
+ if (fd < 0)
return NULL;
if (user_signals == NULL) {
@@ -754,7 +774,7 @@ faulthandler_register_py(PyObject *self,
}
Py_XDECREF(user->file);
- Py_INCREF(file);
+ Py_XINCREF(file);
user->file = file;
user->fd = fd;
user->all_threads = all_threads;
@@ -804,12 +824,41 @@ faulthandler_unregister_py(PyObject *self, PyObject *args)
#endif /* FAULTHANDLER_USER */
+static void
+faulthandler_suppress_crash_report(void)
+{
+#ifdef MS_WINDOWS
+ UINT mode;
+
+ /* Configure Windows to not display the Windows Error Reporting dialog */
+ mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
+ SetErrorMode(mode | SEM_NOGPFAULTERRORBOX);
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit rl;
+
+ /* Disable creation of core dump */
+ if (getrlimit(RLIMIT_CORE, &rl) != 0) {
+ rl.rlim_cur = 0;
+ setrlimit(RLIMIT_CORE, &rl);
+ }
+#endif
+
+#ifdef _MSC_VER
+ /* Visual Studio: configure abort() to not display an error message nor
+ open a popup asking to report the fault. */
+ _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+#endif
+}
+
static PyObject *
faulthandler_read_null(PyObject *self, PyObject *args)
{
volatile int *x;
volatile int y;
+ faulthandler_suppress_crash_report();
x = NULL;
y = *x;
return PyLong_FromLong(y);
@@ -819,6 +868,7 @@ faulthandler_read_null(PyObject *self, PyObject *args)
static void
faulthandler_raise_sigsegv(void)
{
+ faulthandler_suppress_crash_report();
#if defined(MS_WINDOWS)
/* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
handler and then gives back the execution flow to the program (without
@@ -861,6 +911,7 @@ faulthandler_sigfpe(PyObject *self, PyObject *args)
/* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
PowerPC. Use volatile to disable compile-time optimizations. */
volatile int x = 1, y = 0, z;
+ faulthandler_suppress_crash_report();
z = x / y;
/* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
raise it manually. */
@@ -873,39 +924,18 @@ faulthandler_sigfpe(PyObject *self, PyObject *args)
static PyObject *
faulthandler_sigabrt(PyObject *self, PyObject *args)
{
-#ifdef _MSC_VER
- /* Visual Studio: configure abort() to not display an error message nor
- open a popup asking to report the fault. */
- _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
-#endif
+ faulthandler_suppress_crash_report();
abort();
Py_RETURN_NONE;
}
-#ifdef SIGBUS
-static PyObject *
-faulthandler_sigbus(PyObject *self, PyObject *args)
-{
- raise(SIGBUS);
- Py_RETURN_NONE;
-}
-#endif
-
-#ifdef SIGILL
-static PyObject *
-faulthandler_sigill(PyObject *self, PyObject *args)
-{
- raise(SIGILL);
- Py_RETURN_NONE;
-}
-#endif
-
static PyObject *
faulthandler_fatal_error_py(PyObject *self, PyObject *args)
{
char *message;
if (!PyArg_ParseTuple(args, "y:fatal_error", &message))
return NULL;
+ faulthandler_suppress_crash_report();
Py_FatalError(message);
Py_RETURN_NONE;
}
@@ -939,6 +969,7 @@ faulthandler_stack_overflow(PyObject *self)
Py_uintptr_t sp = (Py_uintptr_t)&depth;
Py_uintptr_t stop;
+ faulthandler_suppress_crash_report();
depth = 0;
stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
sp + STACK_OVERFLOW_MAX_SIZE,
@@ -1028,14 +1059,6 @@ static PyMethodDef module_methods[] = {
PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
{"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
-#ifdef SIGBUS
- {"_sigbus", (PyCFunction)faulthandler_sigbus, METH_NOARGS,
- PyDoc_STR("_sigbus(): raise a SIGBUS signal")},
-#endif
-#ifdef SIGILL
- {"_sigill", (PyCFunction)faulthandler_sigill, METH_NOARGS,
- PyDoc_STR("_sigill(): raise a SIGILL signal")},
-#endif
{"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)