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