Coverage Report

Created: 2022-07-08 09:39

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