Coverage Report

Created: 2026-05-16 06:46

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