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