cpython/Modules/faulthandler.c

#include "Python.h"
#include "pycore_initconfig.h"    // _PyStatus_ERR
#include "pycore_pyerrors.h"      // _Py_DumpExtensionModules
#include "pycore_pystate.h"       // _PyThreadState_GET()
#include "pycore_signal.h"        // Py_NSIG
#include "pycore_sysmodule.h"     // _PySys_GetAttr()
#include "pycore_time.h"          // _PyTime_FromSecondsObject()
#include "pycore_traceback.h"     // _Py_DumpTracebackThreads

#ifdef HAVE_UNISTD_H
#  include <unistd.h>             // _exit()
#endif
#include <signal.h>               // sigaction()
#include <stdlib.h>               // abort()
#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H)
#  include <pthread.h>
#endif
#ifdef MS_WINDOWS
#  include <windows.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#  include <sys/resource.h>       // setrlimit()
#endif

#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H)
#  include <linux/auxvec.h>       // AT_MINSIGSTKSZ
#  include <sys/auxv.h>           // getauxval()
#endif


/* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
#define STACK_OVERFLOW_MAX_SIZE

#define PUTS(fd, str)


// clang uses __attribute__((no_sanitize("undefined")))
// GCC 4.9+ uses __attribute__((no_sanitize_undefined))
#if defined(__has_feature)  // Clang
#  if __has_feature(undefined_behavior_sanitizer)
#define _Py_NO_SANITIZE_UNDEFINED
#  endif
#endif
#if defined(__GNUC__) \
    && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))
#define _Py_NO_SANITIZE_UNDEFINED
#endif
#ifndef _Py_NO_SANITIZE_UNDEFINED
#define _Py_NO_SANITIZE_UNDEFINED
#endif


fault_handler_t;

#define fatal_error
#define thread

#ifdef FAULTHANDLER_USER
#define user_signals
user_signal_t;
static void faulthandler_user(int signum);
#endif /* FAULTHANDLER_USER */


static fault_handler_t faulthandler_handlers[] =;
static const size_t faulthandler_nsignals =;

#ifdef FAULTHANDLER_USE_ALT_STACK
#define stack
#define old_stack
#endif


/* Get the file descriptor of a file by calling its fileno() method and then
   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 file descriptor and write the new file into *file_ptr.
   On error, return -1. */

static int
faulthandler_get_fileno(PyObject **file_ptr)
{}

/* Get the state of the current thread: only call this function if the current
   thread holds the GIL. Raise an exception on error. */
static PyThreadState*
get_thread_state(void)
{}

static void
faulthandler_dump_traceback(int fd, int all_threads,
                            PyInterpreterState *interp)
{}

static PyObject*
faulthandler_dump_traceback_py(PyObject *self,
                               PyObject *args, PyObject *kwargs)
{}

static void
faulthandler_disable_fatal_handler(fault_handler_t *handler)
{}


/* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals.

   Display the current Python traceback, restore the previous handler and call
   the previous handler.

   On Windows, don't explicitly call the previous handler, because the Windows
   signal handler would not be called (for an unknown reason). The execution of
   the program continues at faulthandler_fatal_error() exit, but the same
   instruction will raise the same fault (signal), and so the previous handler
   will be called.

   This function is signal-safe and should only call signal-safe functions. */

static void
faulthandler_fatal_error(int signum)
{}

#ifdef MS_WINDOWS
static int
faulthandler_ignore_exception(DWORD code)
{
    /* bpo-30557: ignore exceptions which are not errors */
    if (!(code & 0x80000000)) {
        return 1;
    }
    /* bpo-31701: ignore MSC and COM exceptions
       E0000000 + code */
    if (code == 0xE06D7363 /* MSC exception ("Emsc") */
        || code == 0xE0434352 /* COM Callable Runtime exception ("ECCR") */) {
        return 1;
    }
    /* Interesting exception: log it with the Python traceback */
    return 0;
}

static LONG WINAPI
faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
{
    const int fd = fatal_error.fd;
    DWORD code = exc_info->ExceptionRecord->ExceptionCode;
    DWORD flags = exc_info->ExceptionRecord->ExceptionFlags;

    if (faulthandler_ignore_exception(code)) {
        /* ignore the exception: call the next exception handler */
        return EXCEPTION_CONTINUE_SEARCH;
    }

    PUTS(fd, "Windows fatal exception: ");
    switch (code)
    {
    /* only format most common errors */
    case EXCEPTION_ACCESS_VIOLATION: PUTS(fd, "access violation"); break;
    case EXCEPTION_FLT_DIVIDE_BY_ZERO: PUTS(fd, "float divide by zero"); break;
    case EXCEPTION_FLT_OVERFLOW: PUTS(fd, "float overflow"); break;
    case EXCEPTION_INT_DIVIDE_BY_ZERO: PUTS(fd, "int divide by zero"); break;
    case EXCEPTION_INT_OVERFLOW: PUTS(fd, "integer overflow"); break;
    case EXCEPTION_IN_PAGE_ERROR: PUTS(fd, "page error"); break;
    case EXCEPTION_STACK_OVERFLOW: PUTS(fd, "stack overflow"); break;
    default:
        PUTS(fd, "code 0x");
        _Py_DumpHexadecimal(fd, code, 8);
    }
    PUTS(fd, "\n\n");

    if (code == EXCEPTION_ACCESS_VIOLATION) {
        /* disable signal handler for SIGSEGV */
        for (size_t i=0; i < faulthandler_nsignals; i++) {
            fault_handler_t *handler = &faulthandler_handlers[i];
            if (handler->signum == SIGSEGV) {
                faulthandler_disable_fatal_handler(handler);
                break;
            }
        }
    }

    faulthandler_dump_traceback(fd, fatal_error.all_threads,
                                fatal_error.interp);

    /* call the next exception handler */
    return EXCEPTION_CONTINUE_SEARCH;
}
#endif


#ifdef FAULTHANDLER_USE_ALT_STACK
static int
faulthandler_allocate_stack(void)
{}
#endif


/* Install the handler for fatal signals, faulthandler_fatal_error(). */

static int
faulthandler_enable(void)
{}

static PyObject*
faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
{}

static void
faulthandler_disable(void)
{}

static PyObject*
faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
{}

static PyObject*
faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored))
{}

static void
faulthandler_thread(void *unused)
{}

static void
cancel_dump_traceback_later(void)
{}

#define SEC_TO_US

static char*
format_timeout(PyTime_t us)
{}

static PyObject*
faulthandler_dump_traceback_later(PyObject *self,
                                   PyObject *args, PyObject *kwargs)
{}

static PyObject*
faulthandler_cancel_dump_traceback_later_py(PyObject *self,
                                            PyObject *Py_UNUSED(ignored))
{}


#ifdef FAULTHANDLER_USER
static int
faulthandler_register(int signum, int chain, _Py_sighandler_t *previous_p)
{}

/* Handler of user signals (e.g. SIGUSR1).

   Dump the traceback of the current thread, or of all threads if
   thread.all_threads is true.

   This function is signal safe and should only call signal safe functions. */

static void
faulthandler_user(int signum)
{}

static int
check_signum(int signum)
{}

static PyObject*
faulthandler_register_py(PyObject *self,
                         PyObject *args, PyObject *kwargs)
{}

static int
faulthandler_unregister(user_signal_t *user, int signum)
{}

static PyObject*
faulthandler_unregister_py(PyObject *self, PyObject *args)
{}
#endif   /* FAULTHANDLER_USER */


static void
faulthandler_suppress_crash_report(void)
{}

static PyObject* _Py_NO_SANITIZE_UNDEFINED
faulthandler_read_null(PyObject *self, PyObject *args)
{}

static void
faulthandler_raise_sigsegv(void)
{}

static PyObject *
faulthandler_sigsegv(PyObject *self, PyObject *args)
{}

static void _Py_NO_RETURN
faulthandler_fatal_error_thread(void *plock)
{}

static PyObject *
faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
{}

static PyObject* _Py_NO_SANITIZE_UNDEFINED
faulthandler_sigfpe(PyObject *self, PyObject *args)
{}

static PyObject *
faulthandler_sigabrt(PyObject *self, PyObject *args)
{}

#if defined(FAULTHANDLER_USE_ALT_STACK)
#define FAULTHANDLER_STACK_OVERFLOW

static uintptr_t
stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth)
{}

static PyObject *
faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
{}
#endif   /* defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_SIGACTION) */


static int
faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
{}

#ifdef MS_WINDOWS
static PyObject *
faulthandler_raise_exception(PyObject *self, PyObject *args)
{
    unsigned int code, flags = 0;
    if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags))
        return NULL;
    faulthandler_suppress_crash_report();
    RaiseException(code, flags, 0, NULL);
    Py_RETURN_NONE;
}
#endif

PyDoc_STRVAR(module_doc,
"faulthandler module.");

static PyMethodDef module_methods[] =;

static int
PyExec_faulthandler(PyObject *module) {}

static PyModuleDef_Slot faulthandler_slots[] =;

static struct PyModuleDef module_def =;

PyMODINIT_FUNC
PyInit_faulthandler(void)
{}

static int
faulthandler_init_enable(void)
{}

PyStatus
_PyFaulthandler_Init(int enable)
{}

void _PyFaulthandler_Fini(void)
{}