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