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