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