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