Coverage Report

Created: 2025-07-11 06:59

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