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