Coverage Report

Created: 2025-08-09 06:50

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