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