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(¤t_stack, 0, sizeof(current_stack));
1433 if (sigaltstack(NULL, ¤t_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