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