LCOV - code coverage report
Current view: top level - Modules - faulthandler.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 304 464 65.5 %
Date: 2022-07-20 13:12:14 Functions: 27 39 69.2 %
Branches: 139 234 59.4 %

           Branch data     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                 :       3261 : faulthandler_get_fileno(PyObject **file_ptr)
     154                 :            : {
     155                 :            :     PyObject *result;
     156                 :            :     long fd_long;
     157                 :            :     int fd;
     158                 :       3261 :     PyObject *file = *file_ptr;
     159                 :            : 
     160   [ +  +  +  + ]:       4941 :     if (file == NULL || file == Py_None) {
     161                 :       1684 :         PyThreadState *tstate = _PyThreadState_GET();
     162                 :       1684 :         file = _PySys_GetAttr(tstate, &_Py_ID(stderr));
     163         [ -  + ]:       1684 :         if (file == NULL) {
     164                 :          0 :             PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
     165                 :          0 :             return -1;
     166                 :            :         }
     167         [ +  + ]:       1684 :         if (file == Py_None) {
     168                 :          4 :             PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None");
     169                 :          4 :             return -1;
     170                 :            :         }
     171                 :            :     }
     172         [ +  + ]:       1577 :     else if (PyLong_Check(file)) {
     173                 :       1551 :         fd = _PyLong_AsInt(file);
     174   [ -  +  -  - ]:       1551 :         if (fd == -1 && PyErr_Occurred())
     175                 :          0 :             return -1;
     176         [ -  + ]:       1551 :         if (fd < 0) {
     177                 :          0 :             PyErr_SetString(PyExc_ValueError,
     178                 :            :                             "file is not a valid file descripter");
     179                 :          0 :             return -1;
     180                 :            :         }
     181                 :       1551 :         *file_ptr = NULL;
     182                 :       1551 :         return fd;
     183                 :            :     }
     184                 :            : 
     185                 :       1706 :     result = PyObject_CallMethodNoArgs(file, &_Py_ID(fileno));
     186         [ -  + ]:       1706 :     if (result == NULL)
     187                 :          0 :         return -1;
     188                 :            : 
     189                 :       1706 :     fd = -1;
     190         [ +  - ]:       1706 :     if (PyLong_Check(result)) {
     191                 :       1706 :         fd_long = PyLong_AsLong(result);
     192   [ +  -  +  - ]:       1706 :         if (0 <= fd_long && fd_long < INT_MAX)
     193                 :       1706 :             fd = (int)fd_long;
     194                 :            :     }
     195                 :       1706 :     Py_DECREF(result);
     196                 :            : 
     197         [ -  + ]:       1706 :     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                 :       1706 :     result = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
     204         [ +  - ]:       1706 :     if (result != NULL)
     205                 :       1706 :         Py_DECREF(result);
     206                 :            :     else {
     207                 :            :         /* ignore flush() error */
     208                 :          0 :         PyErr_Clear();
     209                 :            :     }
     210                 :       1706 :     *file_ptr = file;
     211                 :       1706 :     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                 :       3259 : get_thread_state(void)
     218                 :            : {
     219                 :       3259 :     PyThreadState *tstate = _PyThreadState_GET();
     220         [ -  + ]:       3259 :     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                 :       3259 :     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                 :       7650 : faulthandler_disable_fatal_handler(fault_handler_t *handler)
     305                 :            : {
     306         [ -  + ]:       7650 :     if (!handler->enabled)
     307                 :          0 :         return;
     308                 :       7650 :     handler->enabled = 0;
     309                 :            : #ifdef HAVE_SIGACTION
     310                 :       7650 :     (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                 :       2569 : faulthandler_allocate_stack(void)
     446                 :            : {
     447         [ +  + ]:       2569 :     if (stack.ss_sp != NULL) {
     448                 :       1033 :         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                 :       1536 :     stack.ss_sp = PyMem_Malloc(stack.ss_size);
     453         [ -  + ]:       1536 :     if (stack.ss_sp == NULL) {
     454                 :            :         PyErr_NoMemory();
     455                 :          0 :         return -1;
     456                 :            :     }
     457                 :            : 
     458                 :       1536 :     int err = sigaltstack(&stack, &old_stack);
     459         [ -  + ]:       1536 :     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                 :       1536 :     return 0;
     468                 :            : }
     469                 :            : #endif
     470                 :            : 
     471                 :            : 
     472                 :            : /* Install the handler for fatal signals, faulthandler_fatal_error(). */
     473                 :            : 
     474                 :            : static int
     475                 :       1612 : faulthandler_enable(void)
     476                 :            : {
     477         [ +  + ]:       1612 :     if (fatal_error.enabled) {
     478                 :         80 :         return 0;
     479                 :            :     }
     480                 :       1532 :     fatal_error.enabled = 1;
     481                 :            : 
     482                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
     483         [ -  + ]:       1532 :     if (faulthandler_allocate_stack() < 0) {
     484                 :          0 :         return -1;
     485                 :            :     }
     486                 :            : #endif
     487                 :            : 
     488         [ +  + ]:       9192 :     for (size_t i=0; i < faulthandler_nsignals; i++) {
     489                 :            :         fault_handler_t *handler;
     490                 :            :         int err;
     491                 :            : 
     492                 :       7660 :         handler = &faulthandler_handlers[i];
     493                 :            :         assert(!handler->enabled);
     494                 :            : #ifdef HAVE_SIGACTION
     495                 :            :         struct sigaction action;
     496                 :       7660 :         action.sa_handler = faulthandler_fatal_error;
     497                 :       7660 :         sigemptyset(&action.sa_mask);
     498                 :            :         /* Do not prevent the signal from being received from within
     499                 :            :            its own signal handler */
     500                 :       7660 :         action.sa_flags = SA_NODEFER;
     501                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
     502                 :            :         assert(stack.ss_sp != NULL);
     503                 :            :         /* Call the signal handler on an alternate signal stack
     504                 :            :            provided by sigaltstack() */
     505                 :       7660 :         action.sa_flags |= SA_ONSTACK;
     506                 :            : #endif
     507                 :       7660 :         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         [ -  + ]:       7660 :         if (err) {
     514                 :          0 :             PyErr_SetFromErrno(PyExc_RuntimeError);
     515                 :          0 :             return -1;
     516                 :            :         }
     517                 :            : 
     518                 :       7660 :         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                 :       1532 :     return 0;
     526                 :            : }
     527                 :            : 
     528                 :            : static PyObject*
     529                 :       1613 : faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
     530                 :            : {
     531                 :            :     static char *kwlist[] = {"file", "all_threads", NULL};
     532                 :       1613 :     PyObject *file = NULL;
     533                 :       1613 :     int all_threads = 1;
     534                 :            :     int fd;
     535                 :            :     PyThreadState *tstate;
     536                 :            : 
     537         [ -  + ]:       1613 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     538                 :            :         "|Oi:enable", kwlist, &file, &all_threads))
     539                 :          0 :         return NULL;
     540                 :            : 
     541                 :       1613 :     fd = faulthandler_get_fileno(&file);
     542         [ +  + ]:       1613 :     if (fd < 0)
     543                 :          1 :         return NULL;
     544                 :            : 
     545                 :       1612 :     tstate = get_thread_state();
     546         [ -  + ]:       1612 :     if (tstate == NULL)
     547                 :          0 :         return NULL;
     548                 :            : 
     549                 :       1612 :     Py_XINCREF(file);
     550                 :       1612 :     Py_XSETREF(fatal_error.file, file);
     551                 :       1612 :     fatal_error.fd = fd;
     552                 :       1612 :     fatal_error.all_threads = all_threads;
     553                 :       1612 :     fatal_error.interp = PyThreadState_GetInterpreter(tstate);
     554                 :            : 
     555         [ -  + ]:       1612 :     if (faulthandler_enable() < 0) {
     556                 :          0 :         return NULL;
     557                 :            :     }
     558                 :            : 
     559                 :       1612 :     Py_RETURN_NONE;
     560                 :            : }
     561                 :            : 
     562                 :            : static void
     563                 :       2964 : faulthandler_disable(void)
     564                 :            : {
     565         [ +  + ]:       2964 :     if (fatal_error.enabled) {
     566                 :       1530 :         fatal_error.enabled = 0;
     567         [ +  + ]:       9180 :         for (size_t i=0; i < faulthandler_nsignals; i++) {
     568                 :            :             fault_handler_t *handler;
     569                 :       7650 :             handler = &faulthandler_handlers[i];
     570                 :       7650 :             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         [ +  + ]:       2964 :     Py_CLEAR(fatal_error.file);
     580                 :       2964 : }
     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                 :        602 : 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                 :        602 :     sigfillset(&set);
     609                 :        602 :     pthread_sigmask(SIG_SETMASK, &set, NULL);
     610                 :            : #endif
     611                 :            : 
     612                 :            :     do {
     613                 :        606 :         st = PyThread_acquire_lock_timed(thread.cancel_event,
     614                 :            :                                          thread.timeout_us, 0);
     615         [ +  + ]:        606 :         if (st == PY_LOCK_ACQUIRED) {
     616                 :        597 :             PyThread_release_lock(thread.cancel_event);
     617                 :        597 :             break;
     618                 :            :         }
     619                 :            :         /* Timeout => dump traceback */
     620                 :            :         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                 :        602 :     PyThread_release_lock(thread.running);
     633                 :        602 : }
     634                 :            : 
     635                 :            : static void
     636                 :       1192 : cancel_dump_traceback_later(void)
     637                 :            : {
     638                 :            :     /* If not scheduled, nothing to cancel */
     639         [ +  + ]:       1192 :     if (!thread.cancel_event) {
     640                 :          1 :         return;
     641                 :            :     }
     642                 :            : 
     643                 :            :     /* Notify cancellation */
     644                 :       1191 :     PyThread_release_lock(thread.cancel_event);
     645                 :            : 
     646                 :            :     /* Wait for thread to join */
     647                 :       1191 :     PyThread_acquire_lock(thread.running, 1);
     648                 :       1191 :     PyThread_release_lock(thread.running);
     649                 :            : 
     650                 :            :     /* The main thread should always hold the cancel_event lock */
     651                 :       1191 :     PyThread_acquire_lock(thread.cancel_event, 1);
     652                 :            : 
     653         [ +  + ]:       1191 :     Py_CLEAR(thread.file);
     654         [ +  + ]:       1191 :     if (thread.header) {
     655                 :        602 :         PyMem_Free(thread.header);
     656                 :        602 :         thread.header = NULL;
     657                 :            :     }
     658                 :            : }
     659                 :            : 
     660                 :            : #define SEC_TO_US (1000 * 1000)
     661                 :            : 
     662                 :            : static char*
     663                 :        602 : 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                 :        602 :     sec = (unsigned long)(us / SEC_TO_US);
     670                 :        602 :     us %= SEC_TO_US;
     671                 :            : 
     672                 :        602 :     min = sec / 60;
     673                 :        602 :     sec %= 60;
     674                 :        602 :     hour = min / 60;
     675                 :        602 :     min %= 60;
     676                 :            : 
     677         [ +  + ]:        602 :     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                 :        595 :         PyOS_snprintf(buffer, sizeof(buffer),
     684                 :            :                       "Timeout (%lu:%02lu:%02lu)!\n",
     685                 :            :                       hour, min, sec);
     686                 :            :     }
     687                 :        602 :     return _PyMem_Strdup(buffer);
     688                 :            : }
     689                 :            : 
     690                 :            : static PyObject*
     691                 :        603 : 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                 :        603 :     int repeat = 0;
     698                 :        603 :     PyObject *file = NULL;
     699                 :            :     int fd;
     700                 :        603 :     int exit = 0;
     701                 :            :     PyThreadState *tstate;
     702                 :            :     char *header;
     703                 :            :     size_t header_len;
     704                 :            : 
     705         [ -  + ]:        603 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     706                 :            :         "O|iOi:dump_traceback_later", kwlist,
     707                 :            :         &timeout_obj, &repeat, &file, &exit))
     708                 :          0 :         return NULL;
     709                 :            : 
     710         [ -  + ]:        603 :     if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
     711                 :            :                                   _PyTime_ROUND_TIMEOUT) < 0) {
     712                 :          0 :         return NULL;
     713                 :            :     }
     714                 :        603 :     timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
     715         [ -  + ]:        603 :     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         [ -  + ]:        603 :     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                 :        603 :     tstate = get_thread_state();
     727         [ -  + ]:        603 :     if (tstate == NULL) {
     728                 :          0 :         return NULL;
     729                 :            :     }
     730                 :            : 
     731                 :        603 :     fd = faulthandler_get_fileno(&file);
     732         [ +  + ]:        603 :     if (fd < 0) {
     733                 :          1 :         return NULL;
     734                 :            :     }
     735                 :            : 
     736         [ +  + ]:        602 :     if (!thread.running) {
     737                 :        523 :         thread.running = PyThread_allocate_lock();
     738         [ -  + ]:        523 :         if (!thread.running) {
     739                 :            :             return PyErr_NoMemory();
     740                 :            :         }
     741                 :            :     }
     742         [ +  + ]:        602 :     if (!thread.cancel_event) {
     743                 :        523 :         thread.cancel_event = PyThread_allocate_lock();
     744   [ +  -  -  + ]:        523 :         if (!thread.cancel_event || !thread.running) {
     745                 :            :             return PyErr_NoMemory();
     746                 :            :         }
     747                 :            : 
     748                 :            :         /* cancel_event starts to be acquired: it's only released to cancel
     749                 :            :            the thread. */
     750                 :        523 :         PyThread_acquire_lock(thread.cancel_event, 1);
     751                 :            :     }
     752                 :            : 
     753                 :            :     /* format the timeout */
     754                 :        602 :     header = format_timeout(timeout_us);
     755         [ -  + ]:        602 :     if (header == NULL) {
     756                 :            :         return PyErr_NoMemory();
     757                 :            :     }
     758                 :        602 :     header_len = strlen(header);
     759                 :            : 
     760                 :            :     /* Cancel previous thread, if running */
     761                 :        602 :     cancel_dump_traceback_later();
     762                 :            : 
     763                 :        602 :     Py_XINCREF(file);
     764                 :        602 :     Py_XSETREF(thread.file, file);
     765                 :        602 :     thread.fd = fd;
     766                 :            :     /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
     767                 :        602 :     thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
     768                 :        602 :     thread.repeat = repeat;
     769                 :        602 :     thread.interp = PyThreadState_GetInterpreter(tstate);
     770                 :        602 :     thread.exit = exit;
     771                 :        602 :     thread.header = header;
     772                 :        602 :     thread.header_len = header_len;
     773                 :            : 
     774                 :            :     /* Arm these locks to serve as events when released */
     775                 :        602 :     PyThread_acquire_lock(thread.running, 1);
     776                 :            : 
     777         [ -  + ]:        602 :     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                 :        602 :     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                 :       1038 : faulthandler_register(int signum, int chain, _Py_sighandler_t *previous_p)
     802                 :            : {
     803                 :            : #ifdef HAVE_SIGACTION
     804                 :            :     struct sigaction action;
     805                 :       1038 :     action.sa_handler = faulthandler_user;
     806                 :       1038 :     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                 :       1038 :     action.sa_flags = SA_RESTART;
     811         [ +  + ]:       1038 :     if (chain) {
     812                 :            :         /* do not prevent the signal from being received from within its
     813                 :            :            own signal handler */
     814                 :       1034 :         action.sa_flags = SA_NODEFER;
     815                 :            :     }
     816                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
     817                 :            :     assert(stack.ss_sp != NULL);
     818                 :            :     /* Call the signal handler on an alternate signal stack
     819                 :            :        provided by sigaltstack() */
     820                 :       1038 :     action.sa_flags |= SA_ONSTACK;
     821                 :            : #endif
     822                 :       1038 :     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                 :       1038 : check_signum(int signum)
     875                 :            : {
     876         [ +  + ]:       6228 :     for (size_t i=0; i < faulthandler_nsignals; i++) {
     877         [ -  + ]:       5190 :         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   [ +  -  -  + ]:       1038 :     if (signum < 1 || Py_NSIG <= signum) {
     886                 :          0 :         PyErr_SetString(PyExc_ValueError, "signal number out of range");
     887                 :          0 :         return 0;
     888                 :            :     }
     889                 :       1038 :     return 1;
     890                 :            : }
     891                 :            : 
     892                 :            : static PyObject*
     893                 :       1038 : 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                 :       1038 :     PyObject *file = NULL;
     899                 :       1038 :     int all_threads = 1;
     900                 :       1038 :     int chain = 0;
     901                 :            :     int fd;
     902                 :            :     user_signal_t *user;
     903                 :            :     _Py_sighandler_t previous;
     904                 :            :     PyThreadState *tstate;
     905                 :            :     int err;
     906                 :            : 
     907         [ -  + ]:       1038 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     908                 :            :         "i|Oii:register", kwlist,
     909                 :            :         &signum, &file, &all_threads, &chain))
     910                 :          0 :         return NULL;
     911                 :            : 
     912         [ -  + ]:       1038 :     if (!check_signum(signum))
     913                 :          0 :         return NULL;
     914                 :            : 
     915                 :       1038 :     tstate = get_thread_state();
     916         [ -  + ]:       1038 :     if (tstate == NULL)
     917                 :          0 :         return NULL;
     918                 :            : 
     919                 :       1038 :     fd = faulthandler_get_fileno(&file);
     920         [ +  + ]:       1038 :     if (fd < 0)
     921                 :          1 :         return NULL;
     922                 :            : 
     923         [ +  + ]:       1037 :     if (user_signals == NULL) {
     924                 :        521 :         user_signals = PyMem_Calloc(Py_NSIG, sizeof(user_signal_t));
     925         [ -  + ]:        521 :         if (user_signals == NULL)
     926                 :            :             return PyErr_NoMemory();
     927                 :            :     }
     928                 :       1037 :     user = &user_signals[signum];
     929                 :            : 
     930         [ +  - ]:       1037 :     if (!user->enabled) {
     931                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
     932         [ -  + ]:       1037 :         if (faulthandler_allocate_stack() < 0) {
     933                 :          0 :             return NULL;
     934                 :            :         }
     935                 :            : #endif
     936                 :            : 
     937                 :       1037 :         err = faulthandler_register(signum, chain, &previous);
     938         [ -  + ]:       1037 :         if (err) {
     939                 :          0 :             PyErr_SetFromErrno(PyExc_OSError);
     940                 :          0 :             return NULL;
     941                 :            :         }
     942                 :            : 
     943                 :       1037 :         user->previous = previous;
     944                 :            :     }
     945                 :            : 
     946                 :       1037 :     Py_XINCREF(file);
     947                 :       1037 :     Py_XSETREF(user->file, file);
     948                 :       1037 :     user->fd = fd;
     949                 :       1037 :     user->all_threads = all_threads;
     950                 :       1037 :     user->chain = chain;
     951                 :       1037 :     user->interp = PyThreadState_GetInterpreter(tstate);
     952                 :       1037 :     user->enabled = 1;
     953                 :            : 
     954                 :       1037 :     Py_RETURN_NONE;
     955                 :            : }
     956                 :            : 
     957                 :            : static int
     958                 :      33865 : faulthandler_unregister(user_signal_t *user, int signum)
     959                 :            : {
     960         [ +  + ]:      33865 :     if (!user->enabled)
     961                 :      32828 :         return 0;
     962                 :       1037 :     user->enabled = 0;
     963                 :            : #ifdef HAVE_SIGACTION
     964                 :       1037 :     (void)sigaction(signum, &user->previous, NULL);
     965                 :            : #else
     966                 :            :     (void)signal(signum, user->previous);
     967                 :            : #endif
     968         [ +  + ]:       1037 :     Py_CLEAR(user->file);
     969                 :       1037 :     user->fd = -1;
     970                 :       1037 :     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                 :            :     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                 :            :         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                 :      45215 : faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
    1200                 :            : {
    1201   [ +  +  -  + ]:      45215 :     Py_VISIT(thread.file);
    1202                 :            : #ifdef FAULTHANDLER_USER
    1203         [ +  + ]:      45215 :     if (user_signals != NULL) {
    1204         [ +  + ]:    2103024 :         for (size_t signum=0; signum < Py_NSIG; signum++)
    1205   [ +  +  -  + ]:    2071160 :             Py_VISIT(user_signals[signum].file);
    1206                 :            :     }
    1207                 :            : #endif
    1208   [ +  +  -  + ]:      45215 :     Py_VISIT(fatal_error.file);
    1209                 :      45215 :     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                 :       1992 : 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                 :       1992 :     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                 :       1992 : PyInit_faulthandler(void)
    1334                 :            : {
    1335                 :       1992 :     return PyModuleDef_Init(&module_def);
    1336                 :            : }
    1337                 :            : 
    1338                 :            : static int
    1339                 :       1094 : faulthandler_init_enable(void)
    1340                 :            : {
    1341                 :       1094 :     PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable");
    1342         [ -  + ]:       1094 :     if (enable == NULL) {
    1343                 :          0 :         return -1;
    1344                 :            :     }
    1345                 :            : 
    1346                 :       1094 :     PyObject *res = PyObject_CallNoArgs(enable);
    1347                 :       1094 :     Py_DECREF(enable);
    1348         [ -  + ]:       1094 :     if (res == NULL) {
    1349                 :          0 :         return -1;
    1350                 :            :     }
    1351                 :       1094 :     Py_DECREF(res);
    1352                 :            : 
    1353                 :       1094 :     return 0;
    1354                 :            : }
    1355                 :            : 
    1356                 :            : PyStatus
    1357                 :       2963 : _PyFaulthandler_Init(int enable)
    1358                 :            : {
    1359                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
    1360                 :       2963 :     memset(&stack, 0, sizeof(stack));
    1361                 :       2963 :     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                 :       2963 :     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                 :       2963 :     unsigned long at_minstack_size = getauxval(AT_MINSIGSTKSZ);
    1372         [ +  - ]:       2963 :     if (at_minstack_size != 0) {
    1373                 :       2963 :         stack.ss_size = SIGSTKSZ + at_minstack_size;
    1374                 :            :     }
    1375                 :            : #endif
    1376                 :            : #endif
    1377                 :            : 
    1378                 :       2963 :     memset(&thread, 0, sizeof(thread));
    1379                 :            : 
    1380         [ +  + ]:       2963 :     if (enable) {
    1381         [ -  + ]:       1094 :         if (faulthandler_init_enable() < 0) {
    1382                 :          0 :             return _PyStatus_ERR("failed to enable faulthandler");
    1383                 :            :         }
    1384                 :            :     }
    1385                 :       2963 :     return _PyStatus_OK();
    1386                 :            : }
    1387                 :            : 
    1388                 :       2963 : void _PyFaulthandler_Fini(void)
    1389                 :            : {
    1390                 :            :     /* later */
    1391         [ +  + ]:       2963 :     if (thread.cancel_event) {
    1392                 :        523 :         cancel_dump_traceback_later();
    1393                 :        523 :         PyThread_release_lock(thread.cancel_event);
    1394                 :        523 :         PyThread_free_lock(thread.cancel_event);
    1395                 :        523 :         thread.cancel_event = NULL;
    1396                 :            :     }
    1397         [ +  + ]:       2963 :     if (thread.running) {
    1398                 :        523 :         PyThread_free_lock(thread.running);
    1399                 :        523 :         thread.running = NULL;
    1400                 :            :     }
    1401                 :            : 
    1402                 :            : #ifdef FAULTHANDLER_USER
    1403                 :            :     /* user */
    1404         [ +  + ]:       2963 :     if (user_signals != NULL) {
    1405         [ +  + ]:      34386 :         for (size_t signum=0; signum < Py_NSIG; signum++) {
    1406                 :      33865 :             faulthandler_unregister(&user_signals[signum], signum);
    1407                 :            :         }
    1408                 :        521 :         PyMem_Free(user_signals);
    1409                 :        521 :         user_signals = NULL;
    1410                 :            :     }
    1411                 :            : #endif
    1412                 :            : 
    1413                 :            :     /* fatal */
    1414                 :       2963 :     faulthandler_disable();
    1415                 :            : 
    1416                 :            : #ifdef FAULTHANDLER_USE_ALT_STACK
    1417         [ +  + ]:       2963 :     if (stack.ss_sp != NULL) {
    1418                 :            :         /* Fetch the current alt stack */
    1419                 :            :         stack_t current_stack;
    1420                 :       1534 :         memset(&current_stack, 0, sizeof(current_stack));
    1421         [ +  - ]:       1534 :         if (sigaltstack(NULL, &current_stack) == 0) {
    1422         [ +  - ]:       1534 :             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                 :       1534 :                 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                 :       1534 :         PyMem_Free(stack.ss_sp);
    1434                 :       1534 :         stack.ss_sp = NULL;
    1435                 :            :     }
    1436                 :            : #endif
    1437                 :       2963 : }

Generated by: LCOV version 1.14