Coverage Report

Created: 2025-07-04 06:49

/src/cpython/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
32
#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
64
#  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
0
    for (size_t i=0; i < faulthandler_nsignals; i++) {
528
0
        fault_handler_t *handler;
529
0
        int err;
530
531
0
        handler = &faulthandler_handlers[i];
532
0
        assert(!handler->enabled);
533
0
#ifdef HAVE_SIGACTION
534
0
        struct sigaction action;
535
0
        action.sa_handler = faulthandler_fatal_error;
536
0
        sigemptyset(&action.sa_mask);
537
        /* Do not prevent the signal from being received from within
538
           its own signal handler */
539
0
        action.sa_flags = SA_NODEFER;
540
0
#ifdef FAULTHANDLER_USE_ALT_STACK
541
0
        assert(stack.ss_sp != NULL);
542
        /* Call the signal handler on an alternate signal stack
543
           provided by sigaltstack() */
544
0
        action.sa_flags |= SA_ONSTACK;
545
0
#endif
546
0
        err = sigaction(handler->signum, &action, &handler->previous);
547
#else
548
        handler->previous = signal(handler->signum,
549
                                   faulthandler_fatal_error);
550
        err = (handler->previous == SIG_ERR);
551
#endif
552
0
        if (err) {
553
0
            PyErr_SetFromErrno(PyExc_RuntimeError);
554
0
            return -1;
555
0
        }
556
557
0
        handler->enabled = 1;
558
0
    }
559
560
#ifdef MS_WINDOWS
561
    assert(fatal_error.exc_handler == NULL);
562
    fatal_error.exc_handler = AddVectoredExceptionHandler(1, faulthandler_exc_handler);
563
#endif
564
0
    return 0;
565
0
}
566
567
static PyObject*
568
faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
569
0
{
570
0
    static char *kwlist[] = {"file", "all_threads", "c_stack", NULL};
571
0
    PyObject *file = NULL;
572
0
    int all_threads = 1;
573
0
    int fd;
574
0
    int c_stack = 1;
575
0
    PyThreadState *tstate;
576
577
0
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
578
0
        "|Opp:enable", kwlist, &file, &all_threads, &c_stack))
579
0
        return NULL;
580
581
0
    fd = faulthandler_get_fileno(&file);
582
0
    if (fd < 0)
583
0
        return NULL;
584
585
0
    tstate = get_thread_state();
586
0
    if (tstate == NULL) {
587
0
        Py_XDECREF(file);
588
0
        return NULL;
589
0
    }
590
591
0
    Py_XSETREF(fatal_error.file, file);
592
0
    fatal_error.fd = fd;
593
0
    fatal_error.all_threads = all_threads;
594
0
    fatal_error.interp = PyThreadState_GetInterpreter(tstate);
595
0
    fatal_error.c_stack = c_stack;
596
597
0
    if (faulthandler_enable() < 0) {
598
0
        return NULL;
599
0
    }
600
601
0
    Py_RETURN_NONE;
602
0
}
603
604
static void
605
faulthandler_disable(void)
606
0
{
607
0
    if (fatal_error.enabled) {
608
0
        fatal_error.enabled = 0;
609
0
        for (size_t i=0; i < faulthandler_nsignals; i++) {
610
0
            fault_handler_t *handler;
611
0
            handler = &faulthandler_handlers[i];
612
0
            faulthandler_disable_fatal_handler(handler);
613
0
        }
614
0
    }
615
#ifdef MS_WINDOWS
616
    if (fatal_error.exc_handler != NULL) {
617
        RemoveVectoredExceptionHandler(fatal_error.exc_handler);
618
        fatal_error.exc_handler = NULL;
619
    }
620
#endif
621
0
    Py_CLEAR(fatal_error.file);
622
0
}
623
624
static PyObject*
625
faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
626
0
{
627
0
    if (!fatal_error.enabled) {
628
0
        Py_RETURN_FALSE;
629
0
    }
630
0
    faulthandler_disable();
631
0
    Py_RETURN_TRUE;
632
0
}
633
634
static PyObject*
635
faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored))
636
0
{
637
0
    return PyBool_FromLong(fatal_error.enabled);
638
0
}
639
640
static void
641
faulthandler_thread(void *unused)
642
0
{
643
0
    PyLockStatus st;
644
0
    const char* errmsg;
645
0
    int ok;
646
0
#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
647
0
    sigset_t set;
648
649
    /* we don't want to receive any signal */
650
0
    sigfillset(&set);
651
0
    pthread_sigmask(SIG_SETMASK, &set, NULL);
652
0
#endif
653
654
0
    do {
655
0
        st = PyThread_acquire_lock_timed(thread.cancel_event,
656
0
                                         thread.timeout_us, 0);
657
0
        if (st == PY_LOCK_ACQUIRED) {
658
0
            PyThread_release_lock(thread.cancel_event);
659
0
            break;
660
0
        }
661
        /* Timeout => dump traceback */
662
0
        assert(st == PY_LOCK_FAILURE);
663
664
0
        (void)_Py_write_noraise(thread.fd, thread.header, (int)thread.header_len);
665
666
0
        errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL);
667
0
        ok = (errmsg == NULL);
668
669
0
        if (thread.exit)
670
0
            _exit(1);
671
0
    } while (ok && thread.repeat);
672
673
    /* The only way out */
674
0
    PyThread_release_lock(thread.running);
675
0
}
676
677
static void
678
cancel_dump_traceback_later(void)
679
0
{
680
    /* If not scheduled, nothing to cancel */
681
0
    if (!thread.cancel_event) {
682
0
        return;
683
0
    }
684
685
    /* Notify cancellation */
686
0
    PyThread_release_lock(thread.cancel_event);
687
688
    /* Wait for thread to join */
689
0
    PyThread_acquire_lock(thread.running, 1);
690
0
    PyThread_release_lock(thread.running);
691
692
    /* The main thread should always hold the cancel_event lock */
693
0
    PyThread_acquire_lock(thread.cancel_event, 1);
694
695
0
    Py_CLEAR(thread.file);
696
0
    if (thread.header) {
697
0
        PyMem_Free(thread.header);
698
0
        thread.header = NULL;
699
0
    }
700
0
}
701
702
0
#define SEC_TO_US (1000 * 1000)
703
704
static char*
705
format_timeout(PyTime_t us)
706
0
{
707
0
    unsigned long sec, min, hour;
708
0
    char buffer[100];
709
710
    /* the downcast is safe: the caller check that 0 < us <= LONG_MAX */
711
0
    sec = (unsigned long)(us / SEC_TO_US);
712
0
    us %= SEC_TO_US;
713
714
0
    min = sec / 60;
715
0
    sec %= 60;
716
0
    hour = min / 60;
717
0
    min %= 60;
718
719
0
    if (us != 0) {
720
0
        PyOS_snprintf(buffer, sizeof(buffer),
721
0
                      "Timeout (%lu:%02lu:%02lu.%06u)!\n",
722
0
                      hour, min, sec, (unsigned int)us);
723
0
    }
724
0
    else {
725
0
        PyOS_snprintf(buffer, sizeof(buffer),
726
0
                      "Timeout (%lu:%02lu:%02lu)!\n",
727
0
                      hour, min, sec);
728
0
    }
729
0
    return _PyMem_Strdup(buffer);
730
0
}
731
732
static PyObject*
733
faulthandler_dump_traceback_later(PyObject *self,
734
                                   PyObject *args, PyObject *kwargs)
735
0
{
736
0
    static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
737
0
    PyObject *timeout_obj;
738
0
    PyTime_t timeout, timeout_us;
739
0
    int repeat = 0;
740
0
    PyObject *file = NULL;
741
0
    int fd;
742
0
    int exit = 0;
743
0
    PyThreadState *tstate;
744
0
    char *header;
745
0
    size_t header_len;
746
747
0
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
748
0
        "O|iOi:dump_traceback_later", kwlist,
749
0
        &timeout_obj, &repeat, &file, &exit))
750
0
        return NULL;
751
752
0
    if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
753
0
                                  _PyTime_ROUND_TIMEOUT) < 0) {
754
0
        return NULL;
755
0
    }
756
0
    timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
757
0
    if (timeout_us <= 0) {
758
0
        PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
759
0
        return NULL;
760
0
    }
761
    /* Limit to LONG_MAX seconds for format_timeout() */
762
0
    if (timeout_us > PY_TIMEOUT_MAX || timeout_us / SEC_TO_US > LONG_MAX) {
763
0
        PyErr_SetString(PyExc_OverflowError,
764
0
                        "timeout value is too large");
765
0
        return NULL;
766
0
    }
767
768
0
    tstate = get_thread_state();
769
0
    if (tstate == NULL) {
770
0
        return NULL;
771
0
    }
772
773
0
    fd = faulthandler_get_fileno(&file);
774
0
    if (fd < 0) {
775
0
        return NULL;
776
0
    }
777
778
0
    if (!thread.running) {
779
0
        thread.running = PyThread_allocate_lock();
780
0
        if (!thread.running) {
781
0
            Py_XDECREF(file);
782
0
            return PyErr_NoMemory();
783
0
        }
784
0
    }
785
0
    if (!thread.cancel_event) {
786
0
        thread.cancel_event = PyThread_allocate_lock();
787
0
        if (!thread.cancel_event || !thread.running) {
788
0
            Py_XDECREF(file);
789
0
            return PyErr_NoMemory();
790
0
        }
791
792
        /* cancel_event starts to be acquired: it's only released to cancel
793
           the thread. */
794
0
        PyThread_acquire_lock(thread.cancel_event, 1);
795
0
    }
796
797
    /* format the timeout */
798
0
    header = format_timeout(timeout_us);
799
0
    if (header == NULL) {
800
0
        Py_XDECREF(file);
801
0
        return PyErr_NoMemory();
802
0
    }
803
0
    header_len = strlen(header);
804
805
    /* Cancel previous thread, if running */
806
0
    cancel_dump_traceback_later();
807
808
0
    Py_XSETREF(thread.file, file);
809
0
    thread.fd = fd;
810
    /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
811
0
    thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
812
0
    thread.repeat = repeat;
813
0
    thread.interp = PyThreadState_GetInterpreter(tstate);
814
0
    thread.exit = exit;
815
0
    thread.header = header;
816
0
    thread.header_len = header_len;
817
818
    /* Arm these locks to serve as events when released */
819
0
    PyThread_acquire_lock(thread.running, 1);
820
821
0
    if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
822
0
        PyThread_release_lock(thread.running);
823
0
        Py_CLEAR(thread.file);
824
0
        PyMem_Free(header);
825
0
        thread.header = NULL;
826
0
        PyErr_SetString(PyExc_RuntimeError,
827
0
                        "unable to start watchdog thread");
828
0
        return NULL;
829
0
    }
830
831
0
    Py_RETURN_NONE;
832
0
}
833
834
static PyObject*
835
faulthandler_cancel_dump_traceback_later_py(PyObject *self,
836
                                            PyObject *Py_UNUSED(ignored))
837
0
{
838
0
    cancel_dump_traceback_later();
839
0
    Py_RETURN_NONE;
840
0
}
841
842
843
#ifdef FAULTHANDLER_USER
844
static int
845
faulthandler_register(int signum, int chain, _Py_sighandler_t *previous_p)
846
0
{
847
0
#ifdef HAVE_SIGACTION
848
0
    struct sigaction action;
849
0
    action.sa_handler = faulthandler_user;
850
0
    sigemptyset(&action.sa_mask);
851
    /* if the signal is received while the kernel is executing a system
852
       call, try to restart the system call instead of interrupting it and
853
       return EINTR. */
854
0
    action.sa_flags = SA_RESTART;
855
0
    if (chain) {
856
        /* do not prevent the signal from being received from within its
857
           own signal handler */
858
0
        action.sa_flags = SA_NODEFER;
859
0
    }
860
0
#ifdef FAULTHANDLER_USE_ALT_STACK
861
0
    assert(stack.ss_sp != NULL);
862
    /* Call the signal handler on an alternate signal stack
863
       provided by sigaltstack() */
864
0
    action.sa_flags |= SA_ONSTACK;
865
0
#endif
866
0
    return sigaction(signum, &action, previous_p);
867
#else
868
    _Py_sighandler_t previous;
869
    previous = signal(signum, faulthandler_user);
870
    if (previous_p != NULL) {
871
        *previous_p = previous;
872
    }
873
    return (previous == SIG_ERR);
874
#endif
875
0
}
876
877
/* Handler of user signals (e.g. SIGUSR1).
878
879
   Dump the traceback of the current thread, or of all threads if
880
   thread.all_threads is true.
881
882
   This function is signal safe and should only call signal safe functions. */
883
884
static void
885
faulthandler_user(int signum)
886
0
{
887
0
    user_signal_t *user;
888
0
    int save_errno = errno;
889
890
0
    user = &user_signals[signum];
891
0
    if (!user->enabled)
892
0
        return;
893
894
0
    faulthandler_dump_traceback(user->fd, user->all_threads, user->interp);
895
896
0
#ifdef HAVE_SIGACTION
897
0
    if (user->chain) {
898
0
        (void)sigaction(signum, &user->previous, NULL);
899
0
        errno = save_errno;
900
901
        /* call the previous signal handler */
902
0
        raise(signum);
903
904
0
        save_errno = errno;
905
0
        (void)faulthandler_register(signum, user->chain, NULL);
906
0
        errno = save_errno;
907
0
    }
908
#else
909
    if (user->chain && user->previous != NULL) {
910
        errno = save_errno;
911
        /* call the previous signal handler */
912
        user->previous(signum);
913
    }
914
#endif
915
0
}
916
917
static int
918
check_signum(int signum)
919
0
{
920
0
    for (size_t i=0; i < faulthandler_nsignals; i++) {
921
0
        if (faulthandler_handlers[i].signum == signum) {
922
0
            PyErr_Format(PyExc_RuntimeError,
923
0
                         "signal %i cannot be registered, "
924
0
                         "use enable() instead",
925
0
                         signum);
926
0
            return 0;
927
0
        }
928
0
    }
929
0
    if (signum < 1 || Py_NSIG <= signum) {
930
0
        PyErr_SetString(PyExc_ValueError, "signal number out of range");
931
0
        return 0;
932
0
    }
933
0
    return 1;
934
0
}
935
936
static PyObject*
937
faulthandler_register_py(PyObject *self,
938
                         PyObject *args, PyObject *kwargs)
939
0
{
940
0
    static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL};
941
0
    int signum;
942
0
    PyObject *file = NULL;
943
0
    int all_threads = 1;
944
0
    int chain = 0;
945
0
    int fd;
946
0
    user_signal_t *user;
947
0
    _Py_sighandler_t previous;
948
0
    PyThreadState *tstate;
949
0
    int err;
950
951
0
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
952
0
        "i|Opp:register", kwlist,
953
0
        &signum, &file, &all_threads, &chain))
954
0
        return NULL;
955
956
0
    if (!check_signum(signum))
957
0
        return NULL;
958
959
0
    tstate = get_thread_state();
960
0
    if (tstate == NULL)
961
0
        return NULL;
962
963
0
    fd = faulthandler_get_fileno(&file);
964
0
    if (fd < 0)
965
0
        return NULL;
966
967
0
    if (user_signals == NULL) {
968
0
        user_signals = PyMem_Calloc(Py_NSIG, sizeof(user_signal_t));
969
0
        if (user_signals == NULL) {
970
0
            Py_XDECREF(file);
971
0
            return PyErr_NoMemory();
972
0
        }
973
0
    }
974
0
    user = &user_signals[signum];
975
976
0
    if (!user->enabled) {
977
0
#ifdef FAULTHANDLER_USE_ALT_STACK
978
0
        if (faulthandler_allocate_stack() < 0) {
979
0
            Py_XDECREF(file);
980
0
            return NULL;
981
0
        }
982
0
#endif
983
984
0
        err = faulthandler_register(signum, chain, &previous);
985
0
        if (err) {
986
0
            PyErr_SetFromErrno(PyExc_OSError);
987
0
            Py_XDECREF(file);
988
0
            return NULL;
989
0
        }
990
991
0
        user->previous = previous;
992
0
    }
993
994
0
    Py_XSETREF(user->file, file);
995
0
    user->fd = fd;
996
0
    user->all_threads = all_threads;
997
0
    user->chain = chain;
998
0
    user->interp = PyThreadState_GetInterpreter(tstate);
999
0
    user->enabled = 1;
1000
1001
0
    Py_RETURN_NONE;
1002
0
}
1003
1004
static int
1005
faulthandler_unregister(user_signal_t *user, int signum)
1006
0
{
1007
0
    if (!user->enabled)
1008
0
        return 0;
1009
0
    user->enabled = 0;
1010
0
#ifdef HAVE_SIGACTION
1011
0
    (void)sigaction(signum, &user->previous, NULL);
1012
#else
1013
    (void)signal(signum, user->previous);
1014
#endif
1015
0
    Py_CLEAR(user->file);
1016
0
    user->fd = -1;
1017
0
    return 1;
1018
0
}
1019
1020
static PyObject*
1021
faulthandler_unregister_py(PyObject *self, PyObject *args)
1022
0
{
1023
0
    int signum;
1024
0
    user_signal_t *user;
1025
0
    int change;
1026
1027
0
    if (!PyArg_ParseTuple(args, "i:unregister", &signum))
1028
0
        return NULL;
1029
1030
0
    if (!check_signum(signum))
1031
0
        return NULL;
1032
1033
0
    if (user_signals == NULL)
1034
0
        Py_RETURN_FALSE;
1035
1036
0
    user = &user_signals[signum];
1037
0
    change = faulthandler_unregister(user, signum);
1038
0
    return PyBool_FromLong(change);
1039
0
}
1040
#endif   /* FAULTHANDLER_USER */
1041
1042
1043
static void
1044
faulthandler_suppress_crash_report(void)
1045
0
{
1046
#ifdef MS_WINDOWS_DESKTOP
1047
    UINT mode;
1048
1049
    /* Configure Windows to not display the Windows Error Reporting dialog */
1050
    mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
1051
    SetErrorMode(mode | SEM_NOGPFAULTERRORBOX);
1052
#endif
1053
1054
0
#ifdef HAVE_SYS_RESOURCE_H
1055
0
    struct rlimit rl;
1056
1057
    /* Disable creation of core dump */
1058
0
    if (getrlimit(RLIMIT_CORE, &rl) == 0) {
1059
0
        rl.rlim_cur = 0;
1060
0
        setrlimit(RLIMIT_CORE, &rl);
1061
0
    }
1062
0
#endif
1063
1064
#ifdef _MSC_VER
1065
    /* Visual Studio: configure abort() to not display an error message nor
1066
       open a popup asking to report the fault. */
1067
    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
1068
#endif
1069
0
}
1070
1071
1072
static void
1073
faulthandler_raise_sigsegv(void)
1074
0
{
1075
0
    faulthandler_suppress_crash_report();
1076
#if defined(MS_WINDOWS)
1077
    /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
1078
       handler and then gives back the execution flow to the program (without
1079
       explicitly calling the previous error handler). In a normal case, the
1080
       SIGSEGV was raised by the kernel because of a fault, and so if the
1081
       program retries to execute the same instruction, the fault will be
1082
       raised again.
1083
1084
       Here the fault is simulated by a fake SIGSEGV signal raised by the
1085
       application. We have to raise SIGSEGV at lease twice: once for
1086
       faulthandler_fatal_error(), and one more time for the previous signal
1087
       handler. */
1088
    while(1)
1089
        raise(SIGSEGV);
1090
#else
1091
0
    raise(SIGSEGV);
1092
0
#endif
1093
0
}
1094
1095
static PyObject *
1096
faulthandler_sigsegv(PyObject *self, PyObject *args)
1097
0
{
1098
0
    int release_gil = 0;
1099
0
    if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil))
1100
0
        return NULL;
1101
1102
0
    if (release_gil) {
1103
0
        Py_BEGIN_ALLOW_THREADS
1104
0
        faulthandler_raise_sigsegv();
1105
0
        Py_END_ALLOW_THREADS
1106
0
    } else {
1107
0
        faulthandler_raise_sigsegv();
1108
0
    }
1109
0
    Py_RETURN_NONE;
1110
0
}
1111
1112
static void _Py_NO_RETURN
1113
faulthandler_fatal_error_thread(void *plock)
1114
0
{
1115
0
    Py_FatalError("in new thread");
1116
0
}
1117
1118
static PyObject *
1119
faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
1120
0
{
1121
0
    long tid;
1122
0
    PyThread_type_lock lock;
1123
1124
0
    faulthandler_suppress_crash_report();
1125
1126
0
    lock = PyThread_allocate_lock();
1127
0
    if (lock == NULL)
1128
0
        return PyErr_NoMemory();
1129
1130
0
    PyThread_acquire_lock(lock, WAIT_LOCK);
1131
1132
0
    tid = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
1133
0
    if (tid == -1) {
1134
0
        PyThread_free_lock(lock);
1135
0
        PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
1136
0
        return NULL;
1137
0
    }
1138
1139
    /* wait until the thread completes: it will never occur, since Py_FatalError()
1140
       exits the process immediately. */
1141
0
    PyThread_acquire_lock(lock, WAIT_LOCK);
1142
0
    PyThread_release_lock(lock);
1143
0
    PyThread_free_lock(lock);
1144
1145
0
    Py_RETURN_NONE;
1146
0
}
1147
1148
static PyObject*
1149
faulthandler_sigfpe(PyObject *self, PyObject *Py_UNUSED(dummy))
1150
0
{
1151
0
    faulthandler_suppress_crash_report();
1152
0
    raise(SIGFPE);
1153
0
    Py_UNREACHABLE();
1154
0
}
1155
1156
static PyObject *
1157
faulthandler_sigabrt(PyObject *self, PyObject *args)
1158
0
{
1159
0
    faulthandler_suppress_crash_report();
1160
0
    abort();
1161
0
    Py_RETURN_NONE;
1162
0
}
1163
1164
#if defined(FAULTHANDLER_USE_ALT_STACK)
1165
#define FAULTHANDLER_STACK_OVERFLOW
1166
1167
static uintptr_t
1168
stack_overflow(uintptr_t min_sp, uintptr_t max_sp, size_t *depth)
1169
0
{
1170
    /* Allocate (at least) 4096 bytes on the stack at each call.
1171
1172
       bpo-23654, bpo-38965: use volatile keyword to prevent tail call
1173
       optimization. */
1174
0
    volatile unsigned char buffer[4096];
1175
0
    uintptr_t sp = (uintptr_t)&buffer;
1176
0
    *depth += 1;
1177
0
    if (sp < min_sp || max_sp < sp)
1178
0
        return sp;
1179
0
    buffer[0] = 1;
1180
0
    buffer[4095] = 0;
1181
0
    return stack_overflow(min_sp, max_sp, depth);
1182
0
}
1183
1184
static PyObject *
1185
faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
1186
0
{
1187
0
    size_t depth, size;
1188
0
    uintptr_t sp = (uintptr_t)&depth;
1189
0
    uintptr_t stop, lower_limit, upper_limit;
1190
1191
0
    faulthandler_suppress_crash_report();
1192
0
    depth = 0;
1193
1194
0
    if (STACK_OVERFLOW_MAX_SIZE <= sp) {
1195
0
        lower_limit = sp - STACK_OVERFLOW_MAX_SIZE;
1196
0
    }
1197
0
    else {
1198
0
        lower_limit = 0;
1199
0
    }
1200
1201
0
    if (UINTPTR_MAX - STACK_OVERFLOW_MAX_SIZE >= sp) {
1202
0
        upper_limit = sp + STACK_OVERFLOW_MAX_SIZE;
1203
0
    }
1204
0
    else {
1205
0
        upper_limit = UINTPTR_MAX;
1206
0
    }
1207
1208
0
    stop = stack_overflow(lower_limit, upper_limit, &depth);
1209
0
    if (sp < stop)
1210
0
        size = stop - sp;
1211
0
    else
1212
0
        size = sp - stop;
1213
0
    PyErr_Format(PyExc_RuntimeError,
1214
0
        "unable to raise a stack overflow (allocated %zu bytes "
1215
0
        "on the stack, %zu recursive calls)",
1216
0
        size, depth);
1217
0
    return NULL;
1218
0
}
1219
#endif   /* defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_SIGACTION) */
1220
1221
1222
static int
1223
faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
1224
0
{
1225
0
    Py_VISIT(thread.file);
1226
0
#ifdef FAULTHANDLER_USER
1227
0
    if (user_signals != NULL) {
1228
0
        for (size_t signum=0; signum < Py_NSIG; signum++)
1229
0
            Py_VISIT(user_signals[signum].file);
1230
0
    }
1231
0
#endif
1232
0
    Py_VISIT(fatal_error.file);
1233
0
    return 0;
1234
0
}
1235
1236
#ifdef MS_WINDOWS
1237
static PyObject *
1238
faulthandler_raise_exception(PyObject *self, PyObject *args)
1239
{
1240
    unsigned int code, flags = 0;
1241
    if (!PyArg_ParseTuple(args, "I|I:_raise_exception", &code, &flags))
1242
        return NULL;
1243
    faulthandler_suppress_crash_report();
1244
    RaiseException(code, flags, 0, NULL);
1245
    Py_RETURN_NONE;
1246
}
1247
#endif
1248
1249
PyDoc_STRVAR(module_doc,
1250
"faulthandler module.");
1251
1252
static PyMethodDef module_methods[] = {
1253
    {"enable",
1254
     _PyCFunction_CAST(faulthandler_py_enable), METH_VARARGS|METH_KEYWORDS,
1255
     PyDoc_STR("enable($module, /, file=sys.stderr, all_threads=True)\n--\n\n"
1256
               "Enable the fault handler.")},
1257
    {"disable", faulthandler_disable_py, METH_NOARGS,
1258
     PyDoc_STR("disable($module, /)\n--\n\n"
1259
               "Disable the fault handler.")},
1260
    {"is_enabled", faulthandler_is_enabled, METH_NOARGS,
1261
     PyDoc_STR("is_enabled($module, /)\n--\n\n"
1262
               "Check if the handler is enabled.")},
1263
    {"dump_traceback",
1264
     _PyCFunction_CAST(faulthandler_dump_traceback_py), METH_VARARGS|METH_KEYWORDS,
1265
     PyDoc_STR("dump_traceback($module, /, file=sys.stderr, all_threads=True)\n--\n\n"
1266
               "Dump the traceback of the current thread, or of all threads "
1267
               "if all_threads is True, into file.")},
1268
     {"dump_c_stack",
1269
      _PyCFunction_CAST(faulthandler_dump_c_stack_py), METH_VARARGS|METH_KEYWORDS,
1270
      PyDoc_STR("dump_c_stack($module, /, file=sys.stderr)\n--\n\n"
1271
              "Dump the C stack of the current thread.")},
1272
    {"dump_traceback_later",
1273
     _PyCFunction_CAST(faulthandler_dump_traceback_later), METH_VARARGS|METH_KEYWORDS,
1274
     PyDoc_STR("dump_traceback_later($module, /, timeout, repeat=False, file=sys.stderr, exit=False)\n--\n\n"
1275
               "Dump the traceback of all threads in timeout seconds,\n"
1276
               "or each timeout seconds if repeat is True. If exit is True, "
1277
               "call _exit(1) which is not safe.")},
1278
    {"cancel_dump_traceback_later",
1279
     faulthandler_cancel_dump_traceback_later_py, METH_NOARGS,
1280
     PyDoc_STR("cancel_dump_traceback_later($module, /)\n--\n\n"
1281
               "Cancel the previous call to dump_traceback_later().")},
1282
#ifdef FAULTHANDLER_USER
1283
    {"register",
1284
     _PyCFunction_CAST(faulthandler_register_py), METH_VARARGS|METH_KEYWORDS,
1285
     PyDoc_STR("register($module, /, signum, file=sys.stderr, all_threads=True, chain=False)\n--\n\n"
1286
               "Register a handler for the signal 'signum': dump the "
1287
               "traceback of the current thread, or of all threads if "
1288
               "all_threads is True, into file.")},
1289
    {"unregister",
1290
     _PyCFunction_CAST(faulthandler_unregister_py), METH_VARARGS,
1291
     PyDoc_STR("unregister($module, signum, /)\n--\n\n"
1292
               "Unregister the handler of the signal "
1293
               "'signum' registered by register().")},
1294
#endif
1295
    {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
1296
     PyDoc_STR("_sigsegv($module, release_gil=False, /)\n--\n\n"
1297
               "Raise a SIGSEGV signal.")},
1298
    {"_fatal_error_c_thread", faulthandler_fatal_error_c_thread, METH_NOARGS,
1299
     PyDoc_STR("_fatal_error_c_thread($module, /)\n--\n\n"
1300
               "Call Py_FatalError() in a new C thread.")},
1301
    {"_sigabrt", faulthandler_sigabrt, METH_NOARGS,
1302
     PyDoc_STR("_sigabrt($module, /)\n--\n\n"
1303
               "Raise a SIGABRT signal.")},
1304
    {"_sigfpe", faulthandler_sigfpe, METH_NOARGS,
1305
     PyDoc_STR("_sigfpe($module, /)\n--\n\n"
1306
               "Raise a SIGFPE signal.")},
1307
#ifdef FAULTHANDLER_STACK_OVERFLOW
1308
    {"_stack_overflow", faulthandler_stack_overflow, METH_NOARGS,
1309
     PyDoc_STR("_stack_overflow($module, /)\n--\n\n"
1310
               "Recursive call to raise a stack overflow.")},
1311
#endif
1312
#ifdef MS_WINDOWS
1313
    {"_raise_exception", faulthandler_raise_exception, METH_VARARGS,
1314
     PyDoc_STR("_raise_exception($module, code, flags=0, /)\n--\n\n"
1315
               "Call RaiseException(code, flags).")},
1316
#endif
1317
    {NULL, NULL}  /* sentinel */
1318
};
1319
1320
static int
1321
0
PyExec_faulthandler(PyObject *module) {
1322
    /* Add constants for unit tests */
1323
#ifdef MS_WINDOWS
1324
    /* RaiseException() codes (prefixed by an underscore) */
1325
    if (PyModule_AddIntConstant(module, "_EXCEPTION_ACCESS_VIOLATION",
1326
                                EXCEPTION_ACCESS_VIOLATION)) {
1327
        return -1;
1328
    }
1329
    if (PyModule_AddIntConstant(module, "_EXCEPTION_INT_DIVIDE_BY_ZERO",
1330
                                EXCEPTION_INT_DIVIDE_BY_ZERO)) {
1331
        return -1;
1332
    }
1333
    if (PyModule_AddIntConstant(module, "_EXCEPTION_STACK_OVERFLOW",
1334
                                EXCEPTION_STACK_OVERFLOW)) {
1335
        return -1;
1336
    }
1337
1338
    /* RaiseException() flags (prefixed by an underscore) */
1339
    if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE",
1340
                                EXCEPTION_NONCONTINUABLE)) {
1341
        return -1;
1342
    }
1343
    if (PyModule_AddIntConstant(module, "_EXCEPTION_NONCONTINUABLE_EXCEPTION",
1344
                                EXCEPTION_NONCONTINUABLE_EXCEPTION)) {
1345
        return -1;
1346
    }
1347
#endif
1348
0
    return 0;
1349
0
}
1350
1351
static PyModuleDef_Slot faulthandler_slots[] = {
1352
    {Py_mod_exec, PyExec_faulthandler},
1353
    // XXX gh-103092: fix isolation.
1354
    //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
1355
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
1356
    {0, NULL}
1357
};
1358
1359
static struct PyModuleDef module_def = {
1360
    PyModuleDef_HEAD_INIT,
1361
    .m_name = "faulthandler",
1362
    .m_doc = module_doc,
1363
    .m_methods = module_methods,
1364
    .m_traverse = faulthandler_traverse,
1365
    .m_slots = faulthandler_slots
1366
};
1367
1368
PyMODINIT_FUNC
1369
PyInit_faulthandler(void)
1370
0
{
1371
0
    return PyModuleDef_Init(&module_def);
1372
0
}
1373
1374
static int
1375
faulthandler_init_enable(void)
1376
0
{
1377
0
    PyObject *enable = PyImport_ImportModuleAttrString("faulthandler", "enable");
1378
0
    if (enable == NULL) {
1379
0
        return -1;
1380
0
    }
1381
1382
0
    PyObject *res = PyObject_CallNoArgs(enable);
1383
0
    Py_DECREF(enable);
1384
0
    if (res == NULL) {
1385
0
        return -1;
1386
0
    }
1387
0
    Py_DECREF(res);
1388
1389
0
    return 0;
1390
0
}
1391
1392
PyStatus
1393
_PyFaulthandler_Init(int enable)
1394
16
{
1395
16
#ifdef FAULTHANDLER_USE_ALT_STACK
1396
16
    memset(&stack, 0, sizeof(stack));
1397
16
    stack.ss_flags = 0;
1398
    /* bpo-21131: allocate dedicated stack of SIGSTKSZ*2 bytes, instead of just
1399
       SIGSTKSZ bytes. Calling the previous signal handler in faulthandler
1400
       signal handler uses more than SIGSTKSZ bytes of stack memory on some
1401
       platforms. */
1402
16
    stack.ss_size = SIGSTKSZ * 2;
1403
16
#ifdef AT_MINSIGSTKSZ
1404
    /* bpo-46968: Query Linux for minimal stack size to ensure signal delivery
1405
       for the hardware running CPython. This OS feature is available in
1406
       Linux kernel version >= 5.14 */
1407
16
    unsigned long at_minstack_size = getauxval(AT_MINSIGSTKSZ);
1408
16
    if (at_minstack_size != 0) {
1409
0
        stack.ss_size = SIGSTKSZ + at_minstack_size;
1410
0
    }
1411
16
#endif
1412
16
#endif
1413
1414
16
    memset(&thread, 0, sizeof(thread));
1415
1416
16
    if (enable) {
1417
0
        if (faulthandler_init_enable() < 0) {
1418
0
            return _PyStatus_ERR("failed to enable faulthandler");
1419
0
        }
1420
0
    }
1421
16
    return _PyStatus_OK();
1422
16
}
1423
1424
void _PyFaulthandler_Fini(void)
1425
0
{
1426
    /* later */
1427
0
    if (thread.cancel_event) {
1428
0
        cancel_dump_traceback_later();
1429
0
        PyThread_release_lock(thread.cancel_event);
1430
0
        PyThread_free_lock(thread.cancel_event);
1431
0
        thread.cancel_event = NULL;
1432
0
    }
1433
0
    if (thread.running) {
1434
0
        PyThread_free_lock(thread.running);
1435
0
        thread.running = NULL;
1436
0
    }
1437
1438
0
#ifdef FAULTHANDLER_USER
1439
    /* user */
1440
0
    if (user_signals != NULL) {
1441
0
        for (size_t signum=0; signum < Py_NSIG; signum++) {
1442
0
            faulthandler_unregister(&user_signals[signum], signum);
1443
0
        }
1444
0
        PyMem_Free(user_signals);
1445
0
        user_signals = NULL;
1446
0
    }
1447
0
#endif
1448
1449
    /* fatal */
1450
0
    faulthandler_disable();
1451
1452
0
#ifdef FAULTHANDLER_USE_ALT_STACK
1453
0
    if (stack.ss_sp != NULL) {
1454
        /* Fetch the current alt stack */
1455
0
        stack_t current_stack;
1456
0
        memset(&current_stack, 0, sizeof(current_stack));
1457
0
        if (sigaltstack(NULL, &current_stack) == 0) {
1458
0
            if (current_stack.ss_sp == stack.ss_sp) {
1459
                /* The current alt stack is the one that we installed.
1460
                 It is safe to restore the old stack that we found when
1461
                 we installed ours */
1462
0
                sigaltstack(&old_stack, NULL);
1463
0
            } else {
1464
                /* Someone switched to a different alt stack and didn't
1465
                   restore ours when they were done (if they're done).
1466
                   There's not much we can do in this unlikely case */
1467
0
            }
1468
0
        }
1469
0
        PyMem_Free(stack.ss_sp);
1470
0
        stack.ss_sp = NULL;
1471
0
    }
1472
0
#endif
1473
0
}