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