LCOV - code coverage report
Current view: top level - Modules - faulthandler.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 307 475 64.6 %
Date: 2022-07-07 18:19:46 Functions: 27 39 69.2 %

          Line data    Source code
       1             : #include "Python.h"
       2             : #include "pycore_initconfig.h"    // _PyStatus_ERR
       3             : #include "pycore_pyerrors.h"      // _Py_DumpExtensionModules
       4             : #include "pycore_pystate.h"       // _PyThreadState_GET()
       5             : #include "pycore_signal.h"        // Py_NSIG
       6             : #include "pycore_traceback.h"     // _Py_DumpTracebackThreads
       7             : 
       8             : #include <object.h>
       9             : #include <signal.h>
      10             : #include <signal.h>
      11             : #include <stdlib.h>               // abort()
      12             : #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) && defined(HAVE_PTHREAD_H)
      13             : #  include <pthread.h>
      14             : #endif
      15             : #ifdef MS_WINDOWS
      16             : #  include <windows.h>
      17             : #endif
      18             : #ifdef HAVE_SYS_RESOURCE_H
      19             : #  include <sys/resource.h>
      20             : #endif
      21             : 
      22             : /* Using an alternative stack requires sigaltstack()
      23             :    and sigaction() SA_ONSTACK */
      24             : #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
      25             : #  define FAULTHANDLER_USE_ALT_STACK
      26             : #endif
      27             : 
      28             : #if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H)
      29             : #  include <linux/auxvec.h>       // AT_MINSIGSTKSZ
      30             : #  include <sys/auxv.h>           // getauxval()
      31             : #endif
      32             : 
      33             : /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */
      34             : #define STACK_OVERFLOW_MAX_SIZE (100 * 1024 * 1024)
      35             : 
      36             : #ifndef MS_WINDOWS
      37             :    /* register() is useless on Windows, because only SIGSEGV, SIGABRT and
      38             :       SIGILL can be handled by the process, and these signals can only be used
      39             :       with enable(), not using register() */
      40             : #  define FAULTHANDLER_USER
      41             : #endif
      42             : 
      43             : #define PUTS(fd, str) _Py_write_noraise(fd, str, strlen(str))
      44             : 
      45             : 
      46             : // clang uses __attribute__((no_sanitize("undefined")))
      47             : // GCC 4.9+ uses __attribute__((no_sanitize_undefined))
      48             : #if defined(__has_feature)  // Clang
      49             : #  if __has_feature(undefined_behavior_sanitizer)
      50             : #    define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined")))
      51             : #  endif
      52             : #endif
      53             : #if defined(__GNUC__) \
      54             :     && ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))
      55             : #  define _Py_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
      56             : #endif
      57             : #ifndef _Py_NO_SANITIZE_UNDEFINED
      58             : #  define _Py_NO_SANITIZE_UNDEFINED
      59             : #endif
      60             : 
      61             : 
      62             : #ifdef HAVE_SIGACTION
      63             : typedef struct sigaction _Py_sighandler_t;
      64             : #else
      65             : typedef PyOS_sighandler_t _Py_sighandler_t;
      66             : #endif
      67             : 
      68             : typedef struct {
      69             :     int signum;
      70             :     int enabled;
      71             :     const char* name;
      72             :     _Py_sighandler_t previous;
      73             :     int all_threads;
      74             : } fault_handler_t;
      75             : 
      76             : static struct {
      77             :     int enabled;
      78             :     PyObject *file;
      79             :     int fd;
      80             :     int all_threads;
      81             :     PyInterpreterState *interp;
      82             : #ifdef MS_WINDOWS
      83             :     void *exc_handler;
      84             : #endif
      85             : } fatal_error = {0, NULL, -1, 0};
      86             : 
      87             : static struct {
      88             :     PyObject *file;
      89             :     int fd;
      90             :     PY_TIMEOUT_T timeout_us;   /* timeout in microseconds */
      91             :     int repeat;
      92             :     PyInterpreterState *interp;
      93             :     int exit;
      94             :     char *header;
      95             :     size_t header_len;
      96             :     /* The main thread always holds this lock. It is only released when
      97             :        faulthandler_thread() is interrupted before this thread exits, or at
      98             :        Python exit. */
      99             :     PyThread_type_lock cancel_event;
     100             :     /* released by child thread when joined */
     101             :     PyThread_type_lock running;
     102             : } thread;
     103             : 
     104             : #ifdef FAULTHANDLER_USER
     105             : typedef struct {
     106             :     int enabled;
     107             :     PyObject *file;
     108             :     int fd;
     109             :     int all_threads;
     110             :     int chain;
     111             :     _Py_sighandler_t previous;
     112             :     PyInterpreterState *interp;
     113             : } user_signal_t;
     114             : 
     115             : static user_signal_t *user_signals;
     116             : 
     117             : static void faulthandler_user(int signum);
     118             : #endif /* FAULTHANDLER_USER */
     119             : 
     120             : 
     121             : static fault_handler_t faulthandler_handlers[] = {
     122             : #ifdef SIGBUS
     123             :     {SIGBUS, 0, "Bus error", },
     124             : #endif
     125             : #ifdef SIGILL
     126             :     {SIGILL, 0, "Illegal instruction", },
     127             : #endif
     128             :     {SIGFPE, 0, "Floating point exception", },
     129             :     {SIGABRT, 0, "Aborted", },
     130             :     /* define SIGSEGV at the end to make it the default choice if searching the
     131             :        handler fails in faulthandler_fatal_error() */
     132             :     {SIGSEGV, 0, "Segmentation fault", }
     133             : };
     134             : static const size_t faulthandler_nsignals = \
     135             :     Py_ARRAY_LENGTH(faulthandler_handlers);
     136             : 
     137             : #ifdef FAULTHANDLER_USE_ALT_STACK
     138             : static stack_t stack;
     139             : static stack_t old_stack;
     140             : #endif
     141             : 
     142             : 
     143             : /* Get the file descriptor of a file by calling its fileno() method and then
     144             :    call its flush() method.
     145             : 
     146             :    If file is NULL or Py_None, use sys.stderr as the new file.
     147             :    If file is an integer, it will be treated as file descriptor.
     148             : 
     149             :    On success, return the file descriptor and write the new file into *file_ptr.
     150             :    On error, return -1. */
     151             : 
     152             : static int
     153        3288 : faulthandler_get_fileno(PyObject **file_ptr)
     154             : {
     155             :     PyObject *result;
     156             :     long fd_long;
     157             :     int fd;
     158        3288 :     PyObject *file = *file_ptr;
     159             : 
     160        4989 :     if (file == NULL || file == Py_None) {
     161        1705 :         PyThreadState *tstate = _PyThreadState_GET();
     162        1705 :         file = _PySys_GetAttr(tstate, &_Py_ID(stderr));
     163        1705 :         if (file == NULL) {
     164           0 :             PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
     165           0 :             return -1;
     166             :         }
     167        1705 :         if (file == Py_None) {
     168           4 :             PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None");
     169           4 :             return -1;
     170             :         }
     171             :     }
     172        1583 :     else if (PyLong_Check(file)) {
     173        1557 :         fd = _PyLong_AsInt(file);
     174        1557 :         if (fd == -1 && PyErr_Occurred())
     175           0 :             return -1;
     176        1557 :         if (fd < 0) {
     177           0 :             PyErr_SetString(PyExc_ValueError,
     178             :                             "file is not a valid file descripter");
     179           0 :             return -1;
     180             :         }
     181        1557 :         *file_ptr = NULL;
     182        1557 :         return fd;
     183             :     }
     184             : 
     185        1727 :     result = PyObject_CallMethodNoArgs(file, &_Py_ID(fileno));
     186        1727 :     if (result == NULL)
     187           0 :         return -1;
     188             : 
     189        1727 :     fd = -1;
     190        1727 :     if (PyLong_Check(result)) {
     191        1727 :         fd_long = PyLong_AsLong(result);
     192        1727 :         if (0 <= fd_long && fd_long < INT_MAX)
     193        1727 :             fd = (int)fd_long;
     194             :     }
     195        1727 :     Py_DECREF(result);
     196             : 
     197        1727 :     if (fd == -1) {
     198           0 :         PyErr_SetString(PyExc_RuntimeError,
     199             :                         "file.fileno() is not a valid file descriptor");
     200           0 :         return -1;
     201             :     }
     202             : 
     203        1727 :     result = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
     204        1727 :     if (result != NULL)
     205        1727 :         Py_DECREF(result);
     206             :     else {
     207             :         /* ignore flush() error */
     208           0 :         PyErr_Clear();
     209             :     }
     210        1727 :     *file_ptr = file;
     211        1727 :     return fd;
     212             : }
     213             : 
     214             : /* Get the state of the current thread: only call this function if the current
     215             :    thread holds the GIL. Raise an exception on error. */
     216             : static PyThreadState*
     217        3286 : get_thread_state(void)
     218             : {
     219        3286 :     PyThreadState *tstate = _PyThreadState_GET();
     220        3286 :     if (tstate == NULL) {
     221             :         /* just in case but very unlikely... */
     222           0 :         PyErr_SetString(PyExc_RuntimeError,
     223             :                         "unable to get the current thread state");
     224           0 :         return NULL;
     225             :     }
     226        3286 :     return tstate;
     227             : }
     228             : 
     229             : static void
     230           5 : faulthandler_dump_traceback(int fd, int all_threads,
     231             :                             PyInterpreterState *interp)
     232             : {
     233             :     static volatile int reentrant = 0;
     234             :     PyThreadState *tstate;
     235             : 
     236           5 :     if (reentrant)
     237           0 :         return;
     238             : 
     239           5 :     reentrant = 1;
     240             : 
     241             :     /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and
     242             :        are thus delivered to the thread that caused the fault. Get the Python
     243             :        thread state of the current thread.
     244             : 
     245             :        PyThreadState_Get() doesn't give the state of the thread that caused the
     246             :        fault if the thread released the GIL, and so this function cannot be
     247             :        used. Read the thread specific storage (TSS) instead: call
     248             :        PyGILState_GetThisThreadState(). */
     249           5 :     tstate = PyGILState_GetThisThreadState();
     250             : 
     251           5 :     if (all_threads) {
     252           1 :         (void)_Py_DumpTracebackThreads(fd, NULL, tstate);
     253             :     }
     254             :     else {
     255           4 :         if (tstate != NULL)
     256           4 :             _Py_DumpTraceback(fd, tstate);
     257             :     }
     258             : 
     259           5 :     reentrant = 0;
     260             : }
     261             : 
     262             : static PyObject*
     263           7 : faulthandler_dump_traceback_py(PyObject *self,
     264             :                                PyObject *args, PyObject *kwargs)
     265             : {
     266             :     static char *kwlist[] = {"file", "all_threads", NULL};
     267           7 :     PyObject *file = NULL;
     268           7 :     int all_threads = 1;
     269             :     PyThreadState *tstate;
     270             :     const char *errmsg;
     271             :     int fd;
     272             : 
     273           7 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     274             :         "|Oi:dump_traceback", kwlist,
     275             :         &file, &all_threads))
     276           0 :         return NULL;
     277             : 
     278           7 :     fd = faulthandler_get_fileno(&file);
     279           7 :     if (fd < 0)
     280           1 :         return NULL;
     281             : 
     282           6 :     tstate = get_thread_state();
     283           6 :     if (tstate == NULL)
     284           0 :         return NULL;
     285             : 
     286           6 :     if (all_threads) {
     287           2 :         errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate);
     288           2 :         if (errmsg != NULL) {
     289           0 :             PyErr_SetString(PyExc_RuntimeError, errmsg);
     290           0 :             return NULL;
     291             :         }
     292             :     }
     293             :     else {
     294           4 :         _Py_DumpTraceback(fd, tstate);
     295             :     }
     296             : 
     297           6 :     if (PyErr_CheckSignals())
     298           0 :         return NULL;
     299             : 
     300           6 :     Py_RETURN_NONE;
     301             : }
     302             : 
     303             : static void
     304        7750 : faulthandler_disable_fatal_handler(fault_handler_t *handler)
     305             : {
     306        7750 :     if (!handler->enabled)
     307           0 :         return;
     308        7750 :     handler->enabled = 0;
     309             : #ifdef HAVE_SIGACTION
     310        7750 :     (void)sigaction(handler->signum, &handler->previous, NULL);
     311             : #else
     312             :     (void)signal(handler->signum, handler->previous);
     313             : #endif
     314             : }
     315             : 
     316             : 
     317             : /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals.
     318             : 
     319             :    Display the current Python traceback, restore the previous handler and call
     320             :    the previous handler.
     321             : 
     322             :    On Windows, don't explicitly call the previous handler, because the Windows
     323             :    signal handler would not be called (for an unknown reason). The execution of
     324             :    the program continues at faulthandler_fatal_error() exit, but the same
     325             :    instruction will raise the same fault (signal), and so the previous handler
     326             :    will be called.
     327             : 
     328             :    This function is signal-safe and should only call signal-safe functions. */
     329             : 
     330             : static void
     331           0 : faulthandler_fatal_error(int signum)
     332             : {
     333           0 :     const int fd = fatal_error.fd;
     334             :     size_t i;
     335           0 :     fault_handler_t *handler = NULL;
     336           0 :     int save_errno = errno;
     337             : 
     338           0 :     if (!fatal_error.enabled)
     339           0 :         return;
     340             : 
     341           0 :     for (i=0; i < faulthandler_nsignals; i++) {
     342           0 :         handler = &faulthandler_handlers[i];
     343           0 :         if (handler->signum == signum)
     344           0 :             break;
     345             :     }
     346           0 :     if (handler == NULL) {
     347             :         /* faulthandler_nsignals == 0 (unlikely) */
     348           0 :         return;
     349             :     }
     350             : 
     351             :     /* restore the previous handler */
     352           0 :     faulthandler_disable_fatal_handler(handler);
     353             : 
     354           0 :     PUTS(fd, "Fatal Python error: ");
     355           0 :     PUTS(fd, handler->name);
     356           0 :     PUTS(fd, "\n\n");
     357             : 
     358           0 :     faulthandler_dump_traceback(fd, fatal_error.all_threads,
     359             :                                 fatal_error.interp);
     360             : 
     361           0 :     _Py_DumpExtensionModules(fd, fatal_error.interp);
     362             : 
     363           0 :     errno = save_errno;
     364             : #ifdef MS_WINDOWS
     365             :     if (signum == SIGSEGV) {
     366             :         /* don't explicitly call the previous handler for SIGSEGV in this signal
     367             :            handler, because the Windows signal handler would not be called */
     368             :         return;
     369             :     }
     370             : #endif
     371             :     /* call the previous signal handler: it is called immediately if we use
     372             :        sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */
     373           0 :     raise(signum);
     374             : }
     375             : 
     376             : #ifdef MS_WINDOWS
     377             : static int
     378             : faulthandler_ignore_exception(DWORD code)
     379             : {
     380             :     /* bpo-30557: ignore exceptions which are not errors */
     381             :     if (!(code & 0x80000000)) {
     382             :         return 1;
     383             :     }
     384             :     /* bpo-31701: ignore MSC and COM exceptions
     385             :        E0000000 + code */
     386             :     if (code == 0xE06D7363 /* MSC exception ("Emsc") */
     387             :         || code == 0xE0434352 /* COM Callable Runtime exception ("ECCR") */) {
     388             :         return 1;
     389             :     }
     390             :     /* Interesting exception: log it with the Python traceback */
     391             :     return 0;
     392             : }
     393             : 
     394             : static LONG WINAPI
     395             : faulthandler_exc_handler(struct _EXCEPTION_POINTERS *exc_info)
     396             : {
     397             :     const int fd = fatal_error.fd;
     398             :     DWORD code = exc_info->ExceptionRecord->ExceptionCode;
     399             :     DWORD flags = exc_info->ExceptionRecord->ExceptionFlags;
     400             : 
     401             :     if (faulthandler_ignore_exception(code)) {
     402             :         /* ignore the exception: call the next exception handler */
     403             :         return EXCEPTION_CONTINUE_SEARCH;
     404             :     }
     405             : 
     406             :     PUTS(fd, "Windows fatal exception: ");
     407             :     switch (code)
     408             :     {
     409             :     /* only format most common errors */
     410             :     case EXCEPTION_ACCESS_VIOLATION: PUTS(fd, "access violation"); break;
     411             :     case EXCEPTION_FLT_DIVIDE_BY_ZERO: PUTS(fd, "float divide by zero"); break;
     412             :     case EXCEPTION_FLT_OVERFLOW: PUTS(fd, "float overflow"); break;
     413             :     case EXCEPTION_INT_DIVIDE_BY_ZERO: PUTS(fd, "int divide by zero"); break;
     414             :     case EXCEPTION_INT_OVERFLOW: PUTS(fd, "integer overflow"); break;
     415             :     case EXCEPTION_IN_PAGE_ERROR: PUTS(fd, "page error"); break;
     416             :     case EXCEPTION_STACK_OVERFLOW: PUTS(fd, "stack overflow"); break;
     417             :     default:
     418             :         PUTS(fd, "code 0x");
     419             :         _Py_DumpHexadecimal(fd, code, 8);
     420             :     }
     421             :     PUTS(fd, "\n\n");
     422             : 
     423             :     if (code == EXCEPTION_ACCESS_VIOLATION) {
     424             :         /* disable signal handler for SIGSEGV */
     425             :         for (size_t i=0; i < faulthandler_nsignals; i++) {
     426             :             fault_handler_t *handler = &faulthandler_handlers[i];
     427             :             if (handler->signum == SIGSEGV) {
     428             :                 faulthandler_disable_fatal_handler(handler);
     429             :                 break;
     430             :             }
     431             :         }
     432             :     }
     433             : 
     434             :     faulthandler_dump_traceback(fd, fatal_error.all_threads,
     435             :                                 fatal_error.interp);
     436             : 
     437             :     /* call the next exception handler */
     438             :     return EXCEPTION_CONTINUE_SEARCH;
     439             : }
     440             : #endif
     441             : 
     442             : 
     443             : #ifdef FAULTHANDLER_USE_ALT_STACK
     444             : static int
     445        2593 : faulthandler_allocate_stack(void)
     446             : {
     447        2593 :     if (stack.ss_sp != NULL) {
     448        1037 :         return 0;
     449             :     }
     450             :     /* Allocate an alternate stack for faulthandler() signal handler
     451             :        to be able to execute a signal handler on a stack overflow error */
     452        1556 :     stack.ss_sp = PyMem_Malloc(stack.ss_size);
     453        1556 :     if (stack.ss_sp == NULL) {
     454           0 :         PyErr_NoMemory();
     455           0 :         return -1;
     456             :     }
     457             : 
     458        1556 :     int err = sigaltstack(&stack, &old_stack);
     459        1556 :     if (err) {
     460             :         /* Release the stack to retry sigaltstack() next time */
     461           0 :         PyMem_Free(stack.ss_sp);
     462           0 :         stack.ss_sp = NULL;
     463             : 
     464           0 :         PyErr_SetFromErrno(PyExc_OSError);
     465           0 :         return -1;
     466             :     }
     467        1556 :     return 0;
     468             : }
     469             : #endif
     470             : 
     471             : 
     472             : /* Install the handler for fatal signals, faulthandler_fatal_error(). */
     473             : 
     474             : static int
     475        1634 : faulthandler_enable(void)
     476             : {
     477        1634 :     if (fatal_error.enabled) {
     478          82 :         return 0;
     479             :     }
     480        1552 :     fatal_error.enabled = 1;
     481             : 
     482             : #ifdef FAULTHANDLER_USE_ALT_STACK
     483        1552 :     if (faulthandler_allocate_stack() < 0) {
     484           0 :         return -1;
     485             :     }
     486             : #endif
     487             : 
     488        9312 :     for (size_t i=0; i < faulthandler_nsignals; i++) {
     489             :         fault_handler_t *handler;
     490             :         int err;
     491             : 
     492        7760 :         handler = &faulthandler_handlers[i];
     493        7760 :         assert(!handler->enabled);
     494             : #ifdef HAVE_SIGACTION
     495             :         struct sigaction action;
     496        7760 :         action.sa_handler = faulthandler_fatal_error;
     497        7760 :         sigemptyset(&action.sa_mask);
     498             :         /* Do not prevent the signal from being received from within
     499             :            its own signal handler */
     500        7760 :         action.sa_flags = SA_NODEFER;
     501             : #ifdef FAULTHANDLER_USE_ALT_STACK
     502        7760 :         assert(stack.ss_sp != NULL);
     503             :         /* Call the signal handler on an alternate signal stack
     504             :            provided by sigaltstack() */
     505        7760 :         action.sa_flags |= SA_ONSTACK;
     506             : #endif
     507        7760 :         err = sigaction(handler->signum, &action, &handler->previous);
     508             : #else
     509             :         handler->previous = signal(handler->signum,
     510             :                                    faulthandler_fatal_error);
     511             :         err = (handler->previous == SIG_ERR);
     512             : #endif
     513        7760 :         if (err) {
     514           0 :             PyErr_SetFromErrno(PyExc_RuntimeError);
     515           0 :             return -1;
     516             :         }
     517             : 
     518        7760 :         handler->enabled = 1;
     519             :     }
     520             : 
     521             : #ifdef MS_WINDOWS
     522             :     assert(fatal_error.exc_handler == NULL);
     523             :     fatal_error.exc_handler = AddVectoredExceptionHandler(1, faulthandler_exc_handler);
     524             : #endif
     525        1552 :     return 0;
     526             : }
     527             : 
     528             : static PyObject*
     529        1635 : faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
     530             : {
     531             :     static char *kwlist[] = {"file", "all_threads", NULL};
     532        1635 :     PyObject *file = NULL;
     533        1635 :     int all_threads = 1;
     534             :     int fd;
     535             :     PyThreadState *tstate;
     536             : 
     537        1635 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     538             :         "|Oi:enable", kwlist, &file, &all_threads))
     539           0 :         return NULL;
     540             : 
     541        1635 :     fd = faulthandler_get_fileno(&file);
     542        1635 :     if (fd < 0)
     543           1 :         return NULL;
     544             : 
     545        1634 :     tstate = get_thread_state();
     546        1634 :     if (tstate == NULL)
     547           0 :         return NULL;
     548             : 
     549        1634 :     Py_XINCREF(file);
     550        1634 :     Py_XSETREF(fatal_error.file, file);
     551        1634 :     fatal_error.fd = fd;
     552        1634 :     fatal_error.all_threads = all_threads;
     553        1634 :     fatal_error.interp = PyThreadState_GetInterpreter(tstate);
     554             : 
     555        1634 :     if (faulthandler_enable() < 0) {
     556           0 :         return NULL;
     557             :     }
     558             : 
     559        1634 :     Py_RETURN_NONE;
     560             : }
     561             : 
     562             : static void
     563        2959 : faulthandler_disable(void)
     564             : {
     565        2959 :     if (fatal_error.enabled) {
     566        1550 :         fatal_error.enabled = 0;
     567        9300 :         for (size_t i=0; i < faulthandler_nsignals; i++) {
     568             :             fault_handler_t *handler;
     569        7750 :             handler = &faulthandler_handlers[i];
     570        7750 :             faulthandler_disable_fatal_handler(handler);
     571             :         }
     572             :     }
     573             : #ifdef MS_WINDOWS
     574             :     if (fatal_error.exc_handler != NULL) {
     575             :         RemoveVectoredExceptionHandler(fatal_error.exc_handler);
     576             :         fatal_error.exc_handler = NULL;
     577             :     }
     578             : #endif
     579        2959 :     Py_CLEAR(fatal_error.file);
     580        2959 : }
     581             : 
     582             : static PyObject*
     583           1 : faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
     584             : {
     585           1 :     if (!fatal_error.enabled) {
     586           0 :         Py_RETURN_FALSE;
     587             :     }
     588           1 :     faulthandler_disable();
     589           1 :     Py_RETURN_TRUE;
     590             : }
     591             : 
     592             : static PyObject*
     593           8 : faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored))
     594             : {
     595           8 :     return PyBool_FromLong(fatal_error.enabled);
     596             : }
     597             : 
     598             : static void
     599         603 : faulthandler_thread(void *unused)
     600             : {
     601             :     PyLockStatus st;
     602             :     const char* errmsg;
     603             :     int ok;
     604             : #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
     605             :     sigset_t set;
     606             : 
     607             :     /* we don't want to receive any signal */
     608         603 :     sigfillset(&set);
     609         603 :     pthread_sigmask(SIG_SETMASK, &set, NULL);
     610             : #endif
     611             : 
     612             :     do {
     613         607 :         st = PyThread_acquire_lock_timed(thread.cancel_event,
     614             :                                          thread.timeout_us, 0);
     615         607 :         if (st == PY_LOCK_ACQUIRED) {
     616         598 :             PyThread_release_lock(thread.cancel_event);
     617         598 :             break;
     618             :         }
     619             :         /* Timeout => dump traceback */
     620           9 :         assert(st == PY_LOCK_FAILURE);
     621             : 
     622           9 :         _Py_write_noraise(thread.fd, thread.header, (int)thread.header_len);
     623             : 
     624           9 :         errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL);
     625           9 :         ok = (errmsg == NULL);
     626             : 
     627           9 :         if (thread.exit)
     628           0 :             _exit(1);
     629           9 :     } while (ok && thread.repeat);
     630             : 
     631             :     /* The only way out */
     632         603 :     PyThread_release_lock(thread.running);
     633         603 : }
     634             : 
     635             : static void
     636        1195 : cancel_dump_traceback_later(void)
     637             : {
     638             :     /* If not scheduled, nothing to cancel */
     639        1195 :     if (!thread.cancel_event) {
     640           1 :         return;
     641             :     }
     642             : 
     643             :     /* Notify cancellation */
     644        1194 :     PyThread_release_lock(thread.cancel_event);
     645             : 
     646             :     /* Wait for thread to join */
     647        1194 :     PyThread_acquire_lock(thread.running, 1);
     648        1194 :     PyThread_release_lock(thread.running);
     649             : 
     650             :     /* The main thread should always hold the cancel_event lock */
     651        1194 :     PyThread_acquire_lock(thread.cancel_event, 1);
     652             : 
     653        1194 :     Py_CLEAR(thread.file);
     654        1194 :     if (thread.header) {
     655         603 :         PyMem_Free(thread.header);
     656         603 :         thread.header = NULL;
     657             :     }
     658             : }
     659             : 
     660             : #define SEC_TO_US (1000 * 1000)
     661             : 
     662             : static char*
     663         603 : format_timeout(_PyTime_t us)
     664             : {
     665             :     unsigned long sec, min, hour;
     666             :     char buffer[100];
     667             : 
     668             :     /* the downcast is safe: the caller check that 0 < us <= LONG_MAX */
     669         603 :     sec = (unsigned long)(us / SEC_TO_US);
     670         603 :     us %= SEC_TO_US;
     671             : 
     672         603 :     min = sec / 60;
     673         603 :     sec %= 60;
     674         603 :     hour = min / 60;
     675         603 :     min %= 60;
     676             : 
     677         603 :     if (us != 0) {
     678           7 :         PyOS_snprintf(buffer, sizeof(buffer),
     679             :                       "Timeout (%lu:%02lu:%02lu.%06u)!\n",
     680             :                       hour, min, sec, (unsigned int)us);
     681             :     }
     682             :     else {
     683         596 :         PyOS_snprintf(buffer, sizeof(buffer),
     684             :                       "Timeout (%lu:%02lu:%02lu)!\n",
     685             :                       hour, min, sec);
     686             :     }
     687         603 :     return _PyMem_Strdup(buffer);
     688             : }
     689             : 
     690             : static PyObject*
     691         604 : faulthandler_dump_traceback_later(PyObject *self,
     692             :                                    PyObject *args, PyObject *kwargs)
     693             : {
     694             :     static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
     695             :     PyObject *timeout_obj;
     696             :     _PyTime_t timeout, timeout_us;
     697         604 :     int repeat = 0;
     698         604 :     PyObject *file = NULL;
     699             :     int fd;
     700         604 :     int exit = 0;
     701             :     PyThreadState *tstate;
     702             :     char *header;
     703             :     size_t header_len;
     704             : 
     705         604 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     706             :         "O|iOi:dump_traceback_later", kwlist,
     707             :         &timeout_obj, &repeat, &file, &exit))
     708           0 :         return NULL;
     709             : 
     710         604 :     if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
     711             :                                   _PyTime_ROUND_TIMEOUT) < 0) {
     712           0 :         return NULL;
     713             :     }
     714         604 :     timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
     715         604 :     if (timeout_us <= 0) {
     716           0 :         PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
     717           0 :         return NULL;
     718             :     }
     719             :     /* Limit to LONG_MAX seconds for format_timeout() */
     720         604 :     if (timeout_us > PY_TIMEOUT_MAX || timeout_us / SEC_TO_US > LONG_MAX) {
     721           0 :         PyErr_SetString(PyExc_OverflowError,
     722             :                         "timeout value is too large");
     723           0 :         return NULL;
     724             :     }
     725             : 
     726         604 :     tstate = get_thread_state();
     727         604 :     if (tstate == NULL) {
     728           0 :         return NULL;
     729             :     }
     730             : 
     731         604 :     fd = faulthandler_get_fileno(&file);
     732         604 :     if (fd < 0) {
     733           1 :         return NULL;
     734             :     }
     735             : 
     736         603 :     if (!thread.running) {
     737         525 :         thread.running = PyThread_allocate_lock();
     738         525 :         if (!thread.running) {
     739           0 :             return PyErr_NoMemory();
     740             :         }
     741             :     }
     742         603 :     if (!thread.cancel_event) {
     743         525 :         thread.cancel_event = PyThread_allocate_lock();
     744         525 :         if (!thread.cancel_event || !thread.running) {
     745           0 :             return PyErr_NoMemory();
     746             :         }
     747             : 
     748             :         /* cancel_event starts to be acquired: it's only released to cancel
     749             :            the thread. */
     750         525 :         PyThread_acquire_lock(thread.cancel_event, 1);
     751             :     }
     752             : 
     753             :     /* format the timeout */
     754         603 :     header = format_timeout(timeout_us);
     755         603 :     if (header == NULL) {
     756           0 :         return PyErr_NoMemory();
     757             :     }
     758         603 :     header_len = strlen(header);
     759             : 
     760             :     /* Cancel previous thread, if running */
     761         603 :     cancel_dump_traceback_later();
     762             : 
     763         603 :     Py_XINCREF(file);
     764         603 :     Py_XSETREF(thread.file, file);
     765         603 :     thread.fd = fd;
     766             :     /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
     767         603 :     thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
     768         603 :     thread.repeat = repeat;
     769         603 :     thread.interp = PyThreadState_GetInterpreter(tstate);
     770         603 :     thread.exit = exit;
     771         603 :     thread.header = header;
     772         603 :     thread.header_len = header_len;
     773             : 
     774             :     /* Arm these locks to serve as events when released */
     775         603 :     PyThread_acquire_lock(thread.running, 1);
     776             : 
     777         603 :     if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
     778           0 :         PyThread_release_lock(thread.running);
     779           0 :         Py_CLEAR(thread.file);
     780           0 :         PyMem_Free(header);
     781           0 :         thread.header = NULL;
     782           0 :         PyErr_SetString(PyExc_RuntimeError,
     783             :                         "unable to start watchdog thread");
     784           0 :         return NULL;
     785             :     }
     786             : 
     787         603 :     Py_RETURN_NONE;
     788             : }
     789             : 
     790             : static PyObject*
     791          67 : faulthandler_cancel_dump_traceback_later_py(PyObject *self,
     792             :                                             PyObject *Py_UNUSED(ignored))
     793             : {
     794          67 :     cancel_dump_traceback_later();
     795          67 :     Py_RETURN_NONE;
     796             : }
     797             : 
     798             : 
     799             : #ifdef FAULTHANDLER_USER
     800             : static int
     801        1042 : faulthandler_register(int signum, int chain, _Py_sighandler_t *previous_p)
     802             : {
     803             : #ifdef HAVE_SIGACTION
     804             :     struct sigaction action;
     805        1042 :     action.sa_handler = faulthandler_user;
     806        1042 :     sigemptyset(&action.sa_mask);
     807             :     /* if the signal is received while the kernel is executing a system
     808             :        call, try to restart the system call instead of interrupting it and
     809             :        return EINTR. */
     810        1042 :     action.sa_flags = SA_RESTART;
     811        1042 :     if (chain) {
     812             :         /* do not prevent the signal from being received from within its
     813             :            own signal handler */
     814        1038 :         action.sa_flags = SA_NODEFER;
     815             :     }
     816             : #ifdef FAULTHANDLER_USE_ALT_STACK
     817        1042 :     assert(stack.ss_sp != NULL);
     818             :     /* Call the signal handler on an alternate signal stack
     819             :        provided by sigaltstack() */
     820        1042 :     action.sa_flags |= SA_ONSTACK;
     821             : #endif
     822        1042 :     return sigaction(signum, &action, previous_p);
     823             : #else
     824             :     _Py_sighandler_t previous;
     825             :     previous = signal(signum, faulthandler_user);
     826             :     if (previous_p != NULL) {
     827             :         *previous_p = previous;
     828             :     }
     829             :     return (previous == SIG_ERR);
     830             : #endif
     831             : }
     832             : 
     833             : /* Handler of user signals (e.g. SIGUSR1).
     834             : 
     835             :    Dump the traceback of the current thread, or of all threads if
     836             :    thread.all_threads is true.
     837             : 
     838             :    This function is signal safe and should only call signal safe functions. */
     839             : 
     840             : static void
     841           5 : faulthandler_user(int signum)
     842             : {
     843             :     user_signal_t *user;
     844           5 :     int save_errno = errno;
     845             : 
     846           5 :     user = &user_signals[signum];
     847           5 :     if (!user->enabled)
     848           0 :         return;
     849             : 
     850           5 :     faulthandler_dump_traceback(user->fd, user->all_threads, user->interp);
     851             : 
     852             : #ifdef HAVE_SIGACTION
     853           5 :     if (user->chain) {
     854           1 :         (void)sigaction(signum, &user->previous, NULL);
     855           1 :         errno = save_errno;
     856             : 
     857             :         /* call the previous signal handler */
     858           1 :         raise(signum);
     859             : 
     860           1 :         save_errno = errno;
     861           1 :         (void)faulthandler_register(signum, user->chain, NULL);
     862           1 :         errno = save_errno;
     863             :     }
     864             : #else
     865             :     if (user->chain) {
     866             :         errno = save_errno;
     867             :         /* call the previous signal handler */
     868             :         user->previous(signum);
     869             :     }
     870             : #endif
     871             : }
     872             : 
     873             : static int
     874        1042 : check_signum(int signum)
     875             : {
     876        6252 :     for (size_t i=0; i < faulthandler_nsignals; i++) {
     877        5210 :         if (faulthandler_handlers[i].signum == signum) {
     878           0 :             PyErr_Format(PyExc_RuntimeError,
     879             :                          "signal %i cannot be registered, "
     880             :                          "use enable() instead",
     881             :                          signum);
     882           0 :             return 0;
     883             :         }
     884             :     }
     885        1042 :     if (signum < 1 || Py_NSIG <= signum) {
     886           0 :         PyErr_SetString(PyExc_ValueError, "signal number out of range");
     887           0 :         return 0;
     888             :     }
     889        1042 :     return 1;
     890             : }
     891             : 
     892             : static PyObject*
     893        1042 : faulthandler_register_py(PyObject *self,
     894             :                          PyObject *args, PyObject *kwargs)
     895             : {
     896             :     static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL};
     897             :     int signum;
     898        1042 :     PyObject *file = NULL;
     899        1042 :     int all_threads = 1;
     900        1042 :     int chain = 0;
     901             :     int fd;
     902             :     user_signal_t *user;
     903             :     _Py_sighandler_t previous;
     904             :     PyThreadState *tstate;
     905             :     int err;
     906             : 
     907        1042 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     908             :         "i|Oii:register", kwlist,
     909             :         &signum, &file, &all_threads, &chain))
     910           0 :         return NULL;
     911             : 
     912        1042 :     if (!check_signum(signum))
     913           0 :         return NULL;
     914             : 
     915        1042 :     tstate = get_thread_state();
     916        1042 :     if (tstate == NULL)
     917           0 :         return NULL;
     918             : 
     919        1042 :     fd = faulthandler_get_fileno(&file);
     920        1042 :     if (fd < 0)
     921           1 :         return NULL;
     922             : 
     923        1041 :     if (user_signals == NULL) {
     924         523 :         user_signals = PyMem_Calloc(Py_NSIG, sizeof(user_signal_t));
     925         523 :         if (user_signals == NULL)
     926           0 :             return PyErr_NoMemory();
     927             :     }
     928        1041 :     user = &user_signals[signum];
     929             : 
     930        1041 :     if (!user->enabled) {
     931             : #ifdef FAULTHANDLER_USE_ALT_STACK
     932        1041 :         if (faulthandler_allocate_stack() < 0) {
     933           0 :             return NULL;
     934             :         }
     935             : #endif
     936             : 
     937        1041 :         err = faulthandler_register(signum, chain, &previous);
     938        1041 :         if (err) {
     939           0 :             PyErr_SetFromErrno(PyExc_OSError);
     940           0 :             return NULL;
     941             :         }
     942             : 
     943        1041 :         user->previous = previous;
     944             :     }
     945             : 
     946        1041 :     Py_XINCREF(file);
     947        1041 :     Py_XSETREF(user->file, file);
     948        1041 :     user->fd = fd;
     949        1041 :     user->all_threads = all_threads;
     950        1041 :     user->chain = chain;
     951        1041 :     user->interp = PyThreadState_GetInterpreter(tstate);
     952        1041 :     user->enabled = 1;
     953             : 
     954        1041 :     Py_RETURN_NONE;
     955             : }
     956             : 
     957             : static int
     958       33995 : faulthandler_unregister(user_signal_t *user, int signum)
     959             : {
     960       33995 :     if (!user->enabled)
     961       32954 :         return 0;
     962        1041 :     user->enabled = 0;
     963             : #ifdef HAVE_SIGACTION
     964        1041 :     (void)sigaction(signum, &user->previous, NULL);
     965             : #else
     966             :     (void)signal(signum, user->previous);
     967             : #endif
     968        1041 :     Py_CLEAR(user->file);
     969        1041 :     user->fd = -1;
     970        1041 :     return 1;
     971             : }
     972             : 
     973             : static PyObject*
     974           0 : faulthandler_unregister_py(PyObject *self, PyObject *args)
     975             : {
     976             :     int signum;
     977             :     user_signal_t *user;
     978             :     int change;
     979             : 
     980           0 :     if (!PyArg_ParseTuple(args, "i:unregister", &signum))
     981           0 :         return NULL;
     982             : 
     983           0 :     if (!check_signum(signum))
     984           0 :         return NULL;
     985             : 
     986           0 :     if (user_signals == NULL)
     987           0 :         Py_RETURN_FALSE;
     988             : 
     989           0 :     user = &user_signals[signum];
     990           0 :     change = faulthandler_unregister(user, signum);
     991           0 :     return PyBool_FromLong(change);
     992             : }
     993             : #endif   /* FAULTHANDLER_USER */
     994             : 
     995             : 
     996             : static void
     997           0 : faulthandler_suppress_crash_report(void)
     998             : {
     999             : #ifdef MS_WINDOWS
    1000             :     UINT mode;
    1001             : 
    1002             :     /* Configure Windows to not display the Windows Error Reporting dialog */
    1003             :     mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
    1004             :     SetErrorMode(mode | SEM_NOGPFAULTERRORBOX);
    1005             : #endif
    1006             : 
    1007             : #ifdef HAVE_SYS_RESOURCE_H
    1008             :     struct rlimit rl;
    1009             : 
    1010             :     /* Disable creation of core dump */
    1011           0 :     if (getrlimit(RLIMIT_CORE, &rl) == 0) {
    1012           0 :         rl.rlim_cur = 0;
    1013           0 :         setrlimit(RLIMIT_CORE, &rl);
    1014             :     }
    1015             : #endif
    1016             : 
    1017             : #ifdef _MSC_VER
    1018             :     /* Visual Studio: configure abort() to not display an error message nor
    1019             :        open a popup asking to report the fault. */
    1020             :     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
    1021             : #endif
    1022           0 : }
    1023             : 
    1024             : static PyObject* _Py_NO_SANITIZE_UNDEFINED
    1025           0 : faulthandler_read_null(PyObject *self, PyObject *args)
    1026             : {
    1027             :     volatile int *x;
    1028             :     volatile int y;
    1029             : 
    1030           0 :     faulthandler_suppress_crash_report();
    1031           0 :     x = NULL;
    1032           0 :     y = *x;
    1033           0 :     return PyLong_FromLong(y);
    1034             : 
    1035             : }
    1036             : 
    1037             : static void
    1038           0 : faulthandler_raise_sigsegv(void)
    1039             : {
    1040           0 :     faulthandler_suppress_crash_report();
    1041             : #if defined(MS_WINDOWS)
    1042             :     /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
    1043             :        handler and then gives back the execution flow to the program (without
    1044             :        explicitly calling the previous error handler). In a normal case, the
    1045             :        SIGSEGV was raised by the kernel because of a fault, and so if the
    1046             :        program retries to execute the same instruction, the fault will be
    1047             :        raised again.
    1048             : 
    1049             :        Here the fault is simulated by a fake SIGSEGV signal raised by the
    1050             :        application. We have to raise SIGSEGV at lease twice: once for
    1051             :        faulthandler_fatal_error(), and one more time for the previous signal
    1052             :        handler. */
    1053             :     while(1)
    1054             :         raise(SIGSEGV);
    1055             : #else
    1056           0 :     raise(SIGSEGV);
    1057             : #endif
    1058           0 : }
    1059             : 
    1060             : static PyObject *
    1061           0 : faulthandler_sigsegv(PyObject *self, PyObject *args)
    1062             : {
    1063           0 :     int release_gil = 0;
    1064           0 :     if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil))
    1065           0 :         return NULL;
    1066             : 
    1067           0 :     if (release_gil) {
    1068           0 :         Py_BEGIN_ALLOW_THREADS
    1069           0 :         faulthandler_raise_sigsegv();
    1070           0 :         Py_END_ALLOW_THREADS
    1071             :     } else {
    1072           0 :         faulthandler_raise_sigsegv();
    1073             :     }
    1074           0 :     Py_RETURN_NONE;
    1075             : }
    1076             : 
    1077             : static void _Py_NO_RETURN
    1078           0 : faulthandler_fatal_error_thread(void *plock)
    1079             : {
    1080           0 :     Py_FatalError("in new thread");
    1081             : }
    1082             : 
    1083             : static PyObject *
    1084           0 : faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
    1085             : {
    1086             :     long thread;
    1087             :     PyThread_type_lock lock;
    1088             : 
    1089           0 :     faulthandler_suppress_crash_report();
    1090             : 
    1091           0 :     lock = PyThread_allocate_lock();
    1092           0 :     if (lock == NULL)
    1093           0 :         return PyErr_NoMemory();
    1094             : 
    1095           0 :     PyThread_acquire_lock(lock, WAIT_LOCK);
    1096             : 
    1097           0 :     thread = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
    1098           0 :     if (thread == -1) {
    1099           0 :         PyThread_free_lock(lock);
    1100           0 :         PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
    1101           0 :         return NULL;
    1102             :     }
    1103             : 
    1104             :     /* wait until the thread completes: it will never occur, since Py_FatalError()
    1105             :        exits the process immediately. */
    1106           0 :     PyThread_acquire_lock(lock, WAIT_LOCK);
    1107           0 :     PyThread_release_lock(lock);
    1108           0 :     PyThread_free_lock(lock);
    1109             : 
    1110           0 :     Py_RETURN_NONE;
    1111             : }
    1112             : 
    1113             : static PyObject* _Py_NO_SANITIZE_UNDEFINED
    1114           0 : faulthandler_sigfpe(PyObject *self, PyObject *args)
    1115             : {
    1116           0 :     faulthandler_suppress_crash_report();
    1117             : 
    1118             :     /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
    1119             :        PowerPC. Use volatile to disable compile-time optimizations. */
    1120           0 :     volatile int x = 1, y = 0, z;
    1121           0 :     z = x / y;
    1122             : 
    1123             :     /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
    1124             :        raise it manually. */
    1125           0 :     raise(SIGFPE);
    1126             : 
    1127             :     /* This line is never reached, but we pretend to make something with z
    1128             :        to silence a compiler warning. */
    1129           0 :     return PyLong_FromLong(z);
    1130             : }
    1131             : 
    1132             : static PyObject *
    1133           0 : faulthandler_sigabrt(PyObject *self, PyObject *args)
    1134             : {
    1135           0 :     faulthandler_suppress_crash_report();
    1136           0 :     abort();
    1137             :     Py_RETURN_NONE;
    1138             : }
    1139             : 
    1140             : #if defined(FAULTHANDLER_USE_ALT_STACK)
    1141             : #define FAULTHANDLER_STACK_OVERFLOW
    1142             : 
    1143             : static uintptr_t
    1144           0 : stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth)
    1145             : {
    1146             :     /* Allocate (at least) 4096 bytes on the stack at each call.
    1147             : 
    1148             :        bpo-23654, bpo-38965: use volatile keyword to prevent tail call
    1149             :        optimization. */
    1150             :     volatile unsigned char buffer[4096];
    1151           0 :     uintptr_t sp = (uintptr_t)&buffer;
    1152           0 :     *depth += 1;
    1153           0 :     if (sp < min_sp || max_sp < sp)
    1154           0 :         return sp;
    1155           0 :     buffer[0] = 1;
    1156           0 :     buffer[4095] = 0;
    1157           0 :     return stack_overflow(min_sp, max_sp, depth);
    1158             : }
    1159             : 
    1160             : static PyObject *
    1161           0 : faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
    1162             : {
    1163             :     size_t depth, size;
    1164           0 :     uintptr_t sp = (uintptr_t)&depth;
    1165             :     uintptr_t stop, lower_limit, upper_limit;
    1166             : 
    1167           0 :     faulthandler_suppress_crash_report();
    1168           0 :     depth = 0;
    1169             : 
    1170           0 :     if (STACK_OVERFLOW_MAX_SIZE <= sp) {
    1171           0 :         lower_limit = sp - STACK_OVERFLOW_MAX_SIZE;
    1172             :     }
    1173             :     else {
    1174           0 :         lower_limit = 0;
    1175             :     }
    1176             : 
    1177           0 :     if (UINTPTR_MAX - STACK_OVERFLOW_MAX_SIZE >= sp) {
    1178           0 :         upper_limit = sp + STACK_OVERFLOW_MAX_SIZE;
    1179             :     }
    1180             :     else {
    1181           0 :         upper_limit = UINTPTR_MAX;
    1182             :     }
    1183             : 
    1184           0 :     stop = stack_overflow(lower_limit, upper_limit, &depth);
    1185           0 :     if (sp < stop)
    1186           0 :         size = stop - sp;
    1187             :     else
    1188           0 :         size = sp - stop;
    1189           0 :     PyErr_Format(PyExc_RuntimeError,
    1190             :         "unable to raise a stack overflow (allocated %zu bytes "
    1191             :         "on the stack, %zu recursive calls)",
    1192             :         size, depth);
    1193           0 :     return NULL;
    1194             : }
    1195             : #endif   /* defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_SIGACTION) */
    1196             : 
    1197             : 
    1198             : static int
    1199       47533 : faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
    1200             : {
    1201       47533 :     Py_VISIT(thread.file);
    1202             : #ifdef FAULTHANDLER_USER
    1203       47533 :     if (user_signals != NULL) {
    1204     2241360 :         for (size_t signum=0; signum < Py_NSIG; signum++)
    1205     2207400 :             Py_VISIT(user_signals[signum].file);
    1206             :     }
    1207             : #endif
    1208       47533 :     Py_VISIT(fatal_error.file);
    1209       47533 :     return 0;
    1210             : }
    1211             : 
    1212             : #ifdef MS_WINDOWS
    1213             : static PyObject *
    1214             : faulthandler_raise_exception(PyObject *self, PyObject *args)
    1215             : {
    1216             :     unsigned int code, flags = 0;
    1217             :     if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags))
    1218             :         return NULL;
    1219             :     faulthandler_suppress_crash_report();
    1220             :     RaiseException(code, flags, 0, NULL);
    1221             :     Py_RETURN_NONE;
    1222             : }
    1223             : #endif
    1224             : 
    1225             : PyDoc_STRVAR(module_doc,
    1226             : "faulthandler module.");
    1227             : 
    1228             : static PyMethodDef module_methods[] = {
    1229             :     {"enable",
    1230             :      _PyCFunction_CAST(faulthandler_py_enable), METH_VARARGS|METH_KEYWORDS,
    1231             :      PyDoc_STR("enable(file=sys.stderr, all_threads=True): "
    1232             :                "enable the fault handler")},
    1233             :     {"disable", faulthandler_disable_py, METH_NOARGS,
    1234             :      PyDoc_STR("disable(): disable the fault handler")},
    1235             :     {"is_enabled", faulthandler_is_enabled, METH_NOARGS,
    1236             :      PyDoc_STR("is_enabled()->bool: check if the handler is enabled")},
    1237             :     {"dump_traceback",
    1238             :      _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_VARARGS|METH_KEYWORDS,
    1239             :      PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=True): "
    1240             :                "dump the traceback of the current thread, or of all threads "
    1241             :                "if all_threads is True, into file")},
    1242             :     {"dump_traceback_later",
    1243             :      _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_VARARGS|METH_KEYWORDS,
    1244             :      PyDoc_STR("dump_traceback_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n"
    1245             :                "dump the traceback of all threads in timeout seconds,\n"
    1246             :                "or each timeout seconds if repeat is True. If exit is True, "
    1247             :                "call _exit(1) which is not safe.")},
    1248             :     {"cancel_dump_traceback_later",
    1249             :      faulthandler_cancel_dump_traceback_later_py, METH_NOARGS,
    1250             :      PyDoc_STR("cancel_dump_traceback_later():\ncancel the previous call "
    1251             :                "to dump_traceback_later().")},
    1252             : #ifdef FAULTHANDLER_USER
    1253             :     {"register",
    1254             :      _PyCFunction_CAST(faulthandler_register_py), METH_VARARGS|METH_KEYWORDS,
    1255             :      PyDoc_STR("register(signum, file=sys.stderr, all_threads=True, chain=False): "
    1256             :                "register a handler for the signal 'signum': dump the "
    1257             :                "traceback of the current thread, or of all threads if "
    1258             :                "all_threads is True, into file")},
    1259             :     {"unregister",
    1260             :      _PyCFunction_CAST(faulthandler_unregister_py), METH_VARARGS|METH_KEYWORDS,
    1261             :      PyDoc_STR("unregister(signum): unregister the handler of the signal "
    1262             :                 "'signum' registered by register()")},
    1263             : #endif
    1264             :     {"_read_null", faulthandler_read_null, METH_NOARGS,
    1265             :      PyDoc_STR("_read_null(): read from NULL, raise "
    1266             :                "a SIGSEGV or SIGBUS signal depending on the platform")},
    1267             :     {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
    1268             :      PyDoc_STR("_sigsegv(release_gil=False): raise a SIGSEGV signal")},
    1269             :     {"_fatal_error_c_thread", faulthandler_fatal_error_c_thread, METH_NOARGS,
    1270             :      PyDoc_STR("fatal_error_c_thread(): "
    1271             :                "call Py_FatalError() in a new C thread.")},
    1272             :     {"_sigabrt", faulthandler_sigabrt, METH_NOARGS,
    1273             :      PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
    1274             :     {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
    1275             :      PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
    1276             : #ifdef FAULTHANDLER_STACK_OVERFLOW
    1277             :     {"_stack_overflow", faulthandler_stack_overflow, METH_NOARGS,
    1278             :      PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")},
    1279             : #endif
    1280             : #ifdef MS_WINDOWS
    1281             :     {"_raise_exception", faulthandler_raise_exception, METH_VARARGS,
    1282             :      PyDoc_STR("raise_exception(code, flags=0): Call RaiseException(code, flags).")},
    1283             : #endif
    1284             :     {NULL, NULL}  /* sentinel */
    1285             : };
    1286             : 
    1287             : static int
    1288        2007 : PyExec_faulthandler(PyObject *module) {
    1289             :     /* Add constants for unit tests */
    1290             : #ifdef MS_WINDOWS
    1291             :     /* RaiseException() codes (prefixed by an underscore) */
    1292             :     if (PyModule_AddIntConstant(module, "_EXCEPTION_ACCESS_VIOLATION",
    1293             :                                 EXCEPTION_ACCESS_VIOLATION)) {
    1294             :         return -1;
    1295             :     }
    1296             :     if (PyModule_AddIntConstant(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO",
    1297             :                                 EXCEPTION_INT_DIVIDE_BY_ZERO)) {
    1298             :         return -1;
    1299             :     }
    1300             :     if (PyModule_AddIntConstant(module, "_EXCEPTION_STACK_OVERFLOW",
    1301             :                                 EXCEPTION_STACK_OVERFLOW)) {
    1302             :         return -1;
    1303             :     }
    1304             : 
    1305             :     /* RaiseException() flags (prefixed by an underscore) */
    1306             :     if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE",
    1307             :                                 EXCEPTION_NONCONTINUABLE)) {
    1308             :         return -1;
    1309             :     }
    1310             :     if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION",
    1311             :                                 EXCEPTION_NONCONTINUABLE_EXCEPTION)) {
    1312             :         return -1;
    1313             :     }
    1314             : #endif
    1315        2007 :     return 0;
    1316             : }
    1317             : 
    1318             : static PyModuleDef_Slot faulthandler_slots[] = {
    1319             :     {Py_mod_exec, PyExec_faulthandler},
    1320             :     {0, NULL}
    1321             : };
    1322             : 
    1323             : static struct PyModuleDef module_def = {
    1324             :     PyModuleDef_HEAD_INIT,
    1325             :     .m_name = "faulthandler",
    1326             :     .m_doc = module_doc,
    1327             :     .m_methods = module_methods,
    1328             :     .m_traverse = faulthandler_traverse,
    1329             :     .m_slots = faulthandler_slots
    1330             : };
    1331             : 
    1332             : PyMODINIT_FUNC
    1333        2007 : PyInit_faulthandler(void)
    1334             : {
    1335        2007 :     return PyModuleDef_Init(&module_def);
    1336             : }
    1337             : 
    1338             : static int
    1339        1114 : faulthandler_init_enable(void)
    1340             : {
    1341        1114 :     PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable");
    1342        1114 :     if (enable == NULL) {
    1343           0 :         return -1;
    1344             :     }
    1345             : 
    1346        1114 :     PyObject *res = PyObject_CallNoArgs(enable);
    1347        1114 :     Py_DECREF(enable);
    1348        1114 :     if (res == NULL) {
    1349           0 :         return -1;
    1350             :     }
    1351        1114 :     Py_DECREF(res);
    1352             : 
    1353        1114 :     return 0;
    1354             : }
    1355             : 
    1356             : PyStatus
    1357        2959 : _PyFaulthandler_Init(int enable)
    1358             : {
    1359             : #ifdef FAULTHANDLER_USE_ALT_STACK
    1360        2959 :     memset(&stack, 0, sizeof(stack));
    1361        2959 :     stack.ss_flags = 0;
    1362             :     /* bpo-21131: allocate dedicated stack of SIGSTKSZ*2 bytes, instead of just
    1363             :        SIGSTKSZ bytes. Calling the previous signal handler in faulthandler
    1364             :        signal handler uses more than SIGSTKSZ bytes of stack memory on some
    1365             :        platforms. */
    1366        2959 :     stack.ss_size = SIGSTKSZ * 2;
    1367             : #ifdef AT_MINSIGSTKSZ
    1368             :     /* bpo-46968: Query Linux for minimal stack size to ensure signal delivery
    1369             :        for the hardware running CPython. This OS feature is available in
    1370             :        Linux kernel version >= 5.14 */
    1371        2959 :     unsigned long at_minstack_size = getauxval(AT_MINSIGSTKSZ);
    1372        2959 :     if (at_minstack_size != 0) {
    1373           0 :         stack.ss_size = SIGSTKSZ + at_minstack_size;
    1374             :     }
    1375             : #endif
    1376             : #endif
    1377             : 
    1378        2959 :     memset(&thread, 0, sizeof(thread));
    1379             : 
    1380        2959 :     if (enable) {
    1381        1114 :         if (faulthandler_init_enable() < 0) {
    1382           0 :             return _PyStatus_ERR("failed to enable faulthandler");
    1383             :         }
    1384             :     }
    1385        2959 :     return _PyStatus_OK();
    1386             : }
    1387             : 
    1388        2958 : void _PyFaulthandler_Fini(void)
    1389             : {
    1390             :     /* later */
    1391        2958 :     if (thread.cancel_event) {
    1392         525 :         cancel_dump_traceback_later();
    1393         525 :         PyThread_release_lock(thread.cancel_event);
    1394         525 :         PyThread_free_lock(thread.cancel_event);
    1395         525 :         thread.cancel_event = NULL;
    1396             :     }
    1397        2958 :     if (thread.running) {
    1398         525 :         PyThread_free_lock(thread.running);
    1399         525 :         thread.running = NULL;
    1400             :     }
    1401             : 
    1402             : #ifdef FAULTHANDLER_USER
    1403             :     /* user */
    1404        2958 :     if (user_signals != NULL) {
    1405       34518 :         for (size_t signum=0; signum < Py_NSIG; signum++) {
    1406       33995 :             faulthandler_unregister(&user_signals[signum], signum);
    1407             :         }
    1408         523 :         PyMem_Free(user_signals);
    1409         523 :         user_signals = NULL;
    1410             :     }
    1411             : #endif
    1412             : 
    1413             :     /* fatal */
    1414        2958 :     faulthandler_disable();
    1415             : 
    1416             : #ifdef FAULTHANDLER_USE_ALT_STACK
    1417        2958 :     if (stack.ss_sp != NULL) {
    1418             :         /* Fetch the current alt stack */
    1419             :         stack_t current_stack;
    1420        1554 :         memset(&current_stack, 0, sizeof(current_stack));
    1421        1554 :         if (sigaltstack(NULL, &current_stack) == 0) {
    1422        1554 :             if (current_stack.ss_sp == stack.ss_sp) {
    1423             :                 /* The current alt stack is the one that we installed.
    1424             :                  It is safe to restore the old stack that we found when
    1425             :                  we installed ours */
    1426        1554 :                 sigaltstack(&old_stack, NULL);
    1427             :             } else {
    1428             :                 /* Someone switched to a different alt stack and didn't
    1429             :                    restore ours when they were done (if they're done).
    1430             :                    There's not much we can do in this unlikely case */
    1431             :             }
    1432             :         }
    1433        1554 :         PyMem_Free(stack.ss_sp);
    1434        1554 :         stack.ss_sp = NULL;
    1435             :     }
    1436             : #endif
    1437        2958 : }

Generated by: LCOV version 1.14