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