Branch data Line data Source code
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 : 3261 : faulthandler_get_fileno(PyObject **file_ptr)
154 : : {
155 : : PyObject *result;
156 : : long fd_long;
157 : : int fd;
158 : 3261 : PyObject *file = *file_ptr;
159 : :
160 [ + + + + ]: 4941 : if (file == NULL || file == Py_None) {
161 : 1684 : PyThreadState *tstate = _PyThreadState_GET();
162 : 1684 : file = _PySys_GetAttr(tstate, &_Py_ID(stderr));
163 [ - + ]: 1684 : if (file == NULL) {
164 : 0 : PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
165 : 0 : return -1;
166 : : }
167 [ + + ]: 1684 : if (file == Py_None) {
168 : 4 : PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None");
169 : 4 : return -1;
170 : : }
171 : : }
172 [ + + ]: 1577 : else if (PyLong_Check(file)) {
173 : 1551 : fd = _PyLong_AsInt(file);
174 [ - + - - ]: 1551 : if (fd == -1 && PyErr_Occurred())
175 : 0 : return -1;
176 [ - + ]: 1551 : if (fd < 0) {
177 : 0 : PyErr_SetString(PyExc_ValueError,
178 : : "file is not a valid file descripter");
179 : 0 : return -1;
180 : : }
181 : 1551 : *file_ptr = NULL;
182 : 1551 : return fd;
183 : : }
184 : :
185 : 1706 : result = PyObject_CallMethodNoArgs(file, &_Py_ID(fileno));
186 [ - + ]: 1706 : if (result == NULL)
187 : 0 : return -1;
188 : :
189 : 1706 : fd = -1;
190 [ + - ]: 1706 : if (PyLong_Check(result)) {
191 : 1706 : fd_long = PyLong_AsLong(result);
192 [ + - + - ]: 1706 : if (0 <= fd_long && fd_long < INT_MAX)
193 : 1706 : fd = (int)fd_long;
194 : : }
195 : 1706 : Py_DECREF(result);
196 : :
197 [ - + ]: 1706 : if (fd == -1) {
198 : 0 : PyErr_SetString(PyExc_RuntimeError,
199 : : "file.fileno() is not a valid file descriptor");
200 : 0 : return -1;
201 : : }
202 : :
203 : 1706 : result = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
204 [ + - ]: 1706 : if (result != NULL)
205 : 1706 : Py_DECREF(result);
206 : : else {
207 : : /* ignore flush() error */
208 : 0 : PyErr_Clear();
209 : : }
210 : 1706 : *file_ptr = file;
211 : 1706 : 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 : 3259 : get_thread_state(void)
218 : : {
219 : 3259 : PyThreadState *tstate = _PyThreadState_GET();
220 [ - + ]: 3259 : if (tstate == NULL) {
221 : : /* just in case but very unlikely... */
222 : 0 : PyErr_SetString(PyExc_RuntimeError,
223 : : "unable to get the current thread state");
224 : 0 : return NULL;
225 : : }
226 : 3259 : return tstate;
227 : : }
228 : :
229 : : static void
230 : 5 : faulthandler_dump_traceback(int fd, int all_threads,
231 : : PyInterpreterState *interp)
232 : : {
233 : : static volatile int reentrant = 0;
234 : : PyThreadState *tstate;
235 : :
236 [ - + ]: 5 : if (reentrant)
237 : 0 : return;
238 : :
239 : 5 : 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 : 5 : tstate = PyGILState_GetThisThreadState();
250 : :
251 [ + + ]: 5 : if (all_threads) {
252 : 1 : (void)_Py_DumpTracebackThreads(fd, NULL, tstate);
253 : : }
254 : : else {
255 [ + - ]: 4 : if (tstate != NULL)
256 : 4 : _Py_DumpTraceback(fd, tstate);
257 : : }
258 : :
259 : 5 : reentrant = 0;
260 : : }
261 : :
262 : : static PyObject*
263 : 7 : faulthandler_dump_traceback_py(PyObject *self,
264 : : PyObject *args, PyObject *kwargs)
265 : : {
266 : : static char *kwlist[] = {"file", "all_threads", NULL};
267 : 7 : PyObject *file = NULL;
268 : 7 : int all_threads = 1;
269 : : PyThreadState *tstate;
270 : : const char *errmsg;
271 : : int fd;
272 : :
273 [ - + ]: 7 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
274 : : "|Oi:dump_traceback", kwlist,
275 : : &file, &all_threads))
276 : 0 : return NULL;
277 : :
278 : 7 : fd = faulthandler_get_fileno(&file);
279 [ + + ]: 7 : if (fd < 0)
280 : 1 : return NULL;
281 : :
282 : 6 : tstate = get_thread_state();
283 [ - + ]: 6 : if (tstate == NULL)
284 : 0 : return NULL;
285 : :
286 [ + + ]: 6 : if (all_threads) {
287 : 2 : errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate);
288 [ - + ]: 2 : if (errmsg != NULL) {
289 : 0 : PyErr_SetString(PyExc_RuntimeError, errmsg);
290 : 0 : return NULL;
291 : : }
292 : : }
293 : : else {
294 : 4 : _Py_DumpTraceback(fd, tstate);
295 : : }
296 : :
297 [ - + ]: 6 : if (PyErr_CheckSignals())
298 : 0 : return NULL;
299 : :
300 : 6 : Py_RETURN_NONE;
301 : : }
302 : :
303 : : static void
304 : 7650 : faulthandler_disable_fatal_handler(fault_handler_t *handler)
305 : : {
306 [ - + ]: 7650 : if (!handler->enabled)
307 : 0 : return;
308 : 7650 : handler->enabled = 0;
309 : : #ifdef HAVE_SIGACTION
310 : 7650 : (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 : 0 : faulthandler_fatal_error(int signum)
332 : : {
333 : 0 : const int fd = fatal_error.fd;
334 : : size_t i;
335 : 0 : fault_handler_t *handler = NULL;
336 : 0 : int save_errno = errno;
337 : :
338 [ # # ]: 0 : if (!fatal_error.enabled)
339 : 0 : return;
340 : :
341 [ # # ]: 0 : for (i=0; i < faulthandler_nsignals; i++) {
342 : 0 : handler = &faulthandler_handlers[i];
343 [ # # ]: 0 : if (handler->signum == signum)
344 : 0 : break;
345 : : }
346 [ # # ]: 0 : if (handler == NULL) {
347 : : /* faulthandler_nsignals == 0 (unlikely) */
348 : 0 : return;
349 : : }
350 : :
351 : : /* restore the previous handler */
352 : 0 : faulthandler_disable_fatal_handler(handler);
353 : :
354 : 0 : PUTS(fd, "Fatal Python error: ");
355 : 0 : PUTS(fd, handler->name);
356 : 0 : PUTS(fd, "\n\n");
357 : :
358 : 0 : faulthandler_dump_traceback(fd, fatal_error.all_threads,
359 : : fatal_error.interp);
360 : :
361 : 0 : _Py_DumpExtensionModules(fd, fatal_error.interp);
362 : :
363 : 0 : 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 : 0 : 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 : 2569 : faulthandler_allocate_stack(void)
446 : : {
447 [ + + ]: 2569 : if (stack.ss_sp != NULL) {
448 : 1033 : 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 : 1536 : stack.ss_sp = PyMem_Malloc(stack.ss_size);
453 [ - + ]: 1536 : if (stack.ss_sp == NULL) {
454 : : PyErr_NoMemory();
455 : 0 : return -1;
456 : : }
457 : :
458 : 1536 : int err = sigaltstack(&stack, &old_stack);
459 [ - + ]: 1536 : if (err) {
460 : : /* Release the stack to retry sigaltstack() next time */
461 : 0 : PyMem_Free(stack.ss_sp);
462 : 0 : stack.ss_sp = NULL;
463 : :
464 : 0 : PyErr_SetFromErrno(PyExc_OSError);
465 : 0 : return -1;
466 : : }
467 : 1536 : return 0;
468 : : }
469 : : #endif
470 : :
471 : :
472 : : /* Install the handler for fatal signals, faulthandler_fatal_error(). */
473 : :
474 : : static int
475 : 1612 : faulthandler_enable(void)
476 : : {
477 [ + + ]: 1612 : if (fatal_error.enabled) {
478 : 80 : return 0;
479 : : }
480 : 1532 : fatal_error.enabled = 1;
481 : :
482 : : #ifdef FAULTHANDLER_USE_ALT_STACK
483 [ - + ]: 1532 : if (faulthandler_allocate_stack() < 0) {
484 : 0 : return -1;
485 : : }
486 : : #endif
487 : :
488 [ + + ]: 9192 : for (size_t i=0; i < faulthandler_nsignals; i++) {
489 : : fault_handler_t *handler;
490 : : int err;
491 : :
492 : 7660 : handler = &faulthandler_handlers[i];
493 : : assert(!handler->enabled);
494 : : #ifdef HAVE_SIGACTION
495 : : struct sigaction action;
496 : 7660 : action.sa_handler = faulthandler_fatal_error;
497 : 7660 : sigemptyset(&action.sa_mask);
498 : : /* Do not prevent the signal from being received from within
499 : : its own signal handler */
500 : 7660 : 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 : 7660 : action.sa_flags |= SA_ONSTACK;
506 : : #endif
507 : 7660 : 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 [ - + ]: 7660 : if (err) {
514 : 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
515 : 0 : return -1;
516 : : }
517 : :
518 : 7660 : 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 : 1532 : return 0;
526 : : }
527 : :
528 : : static PyObject*
529 : 1613 : faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs)
530 : : {
531 : : static char *kwlist[] = {"file", "all_threads", NULL};
532 : 1613 : PyObject *file = NULL;
533 : 1613 : int all_threads = 1;
534 : : int fd;
535 : : PyThreadState *tstate;
536 : :
537 [ - + ]: 1613 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
538 : : "|Oi:enable", kwlist, &file, &all_threads))
539 : 0 : return NULL;
540 : :
541 : 1613 : fd = faulthandler_get_fileno(&file);
542 [ + + ]: 1613 : if (fd < 0)
543 : 1 : return NULL;
544 : :
545 : 1612 : tstate = get_thread_state();
546 [ - + ]: 1612 : if (tstate == NULL)
547 : 0 : return NULL;
548 : :
549 : 1612 : Py_XINCREF(file);
550 : 1612 : Py_XSETREF(fatal_error.file, file);
551 : 1612 : fatal_error.fd = fd;
552 : 1612 : fatal_error.all_threads = all_threads;
553 : 1612 : fatal_error.interp = PyThreadState_GetInterpreter(tstate);
554 : :
555 [ - + ]: 1612 : if (faulthandler_enable() < 0) {
556 : 0 : return NULL;
557 : : }
558 : :
559 : 1612 : Py_RETURN_NONE;
560 : : }
561 : :
562 : : static void
563 : 2964 : faulthandler_disable(void)
564 : : {
565 [ + + ]: 2964 : if (fatal_error.enabled) {
566 : 1530 : fatal_error.enabled = 0;
567 [ + + ]: 9180 : for (size_t i=0; i < faulthandler_nsignals; i++) {
568 : : fault_handler_t *handler;
569 : 7650 : handler = &faulthandler_handlers[i];
570 : 7650 : 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 [ + + ]: 2964 : Py_CLEAR(fatal_error.file);
580 : 2964 : }
581 : :
582 : : static PyObject*
583 : 1 : faulthandler_disable_py(PyObject *self, PyObject *Py_UNUSED(ignored))
584 : : {
585 [ - + ]: 1 : if (!fatal_error.enabled) {
586 : 0 : Py_RETURN_FALSE;
587 : : }
588 : 1 : faulthandler_disable();
589 : 1 : Py_RETURN_TRUE;
590 : : }
591 : :
592 : : static PyObject*
593 : 8 : faulthandler_is_enabled(PyObject *self, PyObject *Py_UNUSED(ignored))
594 : : {
595 : 8 : return PyBool_FromLong(fatal_error.enabled);
596 : : }
597 : :
598 : : static void
599 : 602 : 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 : 602 : sigfillset(&set);
609 : 602 : pthread_sigmask(SIG_SETMASK, &set, NULL);
610 : : #endif
611 : :
612 : : do {
613 : 606 : st = PyThread_acquire_lock_timed(thread.cancel_event,
614 : : thread.timeout_us, 0);
615 [ + + ]: 606 : if (st == PY_LOCK_ACQUIRED) {
616 : 597 : PyThread_release_lock(thread.cancel_event);
617 : 597 : break;
618 : : }
619 : : /* Timeout => dump traceback */
620 : : assert(st == PY_LOCK_FAILURE);
621 : :
622 : 9 : _Py_write_noraise(thread.fd, thread.header, (int)thread.header_len);
623 : :
624 : 9 : errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, NULL);
625 : 9 : ok = (errmsg == NULL);
626 : :
627 [ - + ]: 9 : if (thread.exit)
628 : 0 : _exit(1);
629 [ + - + + ]: 9 : } while (ok && thread.repeat);
630 : :
631 : : /* The only way out */
632 : 602 : PyThread_release_lock(thread.running);
633 : 602 : }
634 : :
635 : : static void
636 : 1192 : cancel_dump_traceback_later(void)
637 : : {
638 : : /* If not scheduled, nothing to cancel */
639 [ + + ]: 1192 : if (!thread.cancel_event) {
640 : 1 : return;
641 : : }
642 : :
643 : : /* Notify cancellation */
644 : 1191 : PyThread_release_lock(thread.cancel_event);
645 : :
646 : : /* Wait for thread to join */
647 : 1191 : PyThread_acquire_lock(thread.running, 1);
648 : 1191 : PyThread_release_lock(thread.running);
649 : :
650 : : /* The main thread should always hold the cancel_event lock */
651 : 1191 : PyThread_acquire_lock(thread.cancel_event, 1);
652 : :
653 [ + + ]: 1191 : Py_CLEAR(thread.file);
654 [ + + ]: 1191 : if (thread.header) {
655 : 602 : PyMem_Free(thread.header);
656 : 602 : thread.header = NULL;
657 : : }
658 : : }
659 : :
660 : : #define SEC_TO_US (1000 * 1000)
661 : :
662 : : static char*
663 : 602 : 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 : 602 : sec = (unsigned long)(us / SEC_TO_US);
670 : 602 : us %= SEC_TO_US;
671 : :
672 : 602 : min = sec / 60;
673 : 602 : sec %= 60;
674 : 602 : hour = min / 60;
675 : 602 : min %= 60;
676 : :
677 [ + + ]: 602 : if (us != 0) {
678 : 7 : PyOS_snprintf(buffer, sizeof(buffer),
679 : : "Timeout (%lu:%02lu:%02lu.%06u)!\n",
680 : : hour, min, sec, (unsigned int)us);
681 : : }
682 : : else {
683 : 595 : PyOS_snprintf(buffer, sizeof(buffer),
684 : : "Timeout (%lu:%02lu:%02lu)!\n",
685 : : hour, min, sec);
686 : : }
687 : 602 : return _PyMem_Strdup(buffer);
688 : : }
689 : :
690 : : static PyObject*
691 : 603 : 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 : 603 : int repeat = 0;
698 : 603 : PyObject *file = NULL;
699 : : int fd;
700 : 603 : int exit = 0;
701 : : PyThreadState *tstate;
702 : : char *header;
703 : : size_t header_len;
704 : :
705 [ - + ]: 603 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
706 : : "O|iOi:dump_traceback_later", kwlist,
707 : : &timeout_obj, &repeat, &file, &exit))
708 : 0 : return NULL;
709 : :
710 [ - + ]: 603 : if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
711 : : _PyTime_ROUND_TIMEOUT) < 0) {
712 : 0 : return NULL;
713 : : }
714 : 603 : timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
715 [ - + ]: 603 : if (timeout_us <= 0) {
716 : 0 : PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
717 : 0 : return NULL;
718 : : }
719 : : /* Limit to LONG_MAX seconds for format_timeout() */
720 [ - + ]: 603 : if (timeout_us > PY_TIMEOUT_MAX || timeout_us / SEC_TO_US > LONG_MAX) {
721 : 0 : PyErr_SetString(PyExc_OverflowError,
722 : : "timeout value is too large");
723 : 0 : return NULL;
724 : : }
725 : :
726 : 603 : tstate = get_thread_state();
727 [ - + ]: 603 : if (tstate == NULL) {
728 : 0 : return NULL;
729 : : }
730 : :
731 : 603 : fd = faulthandler_get_fileno(&file);
732 [ + + ]: 603 : if (fd < 0) {
733 : 1 : return NULL;
734 : : }
735 : :
736 [ + + ]: 602 : if (!thread.running) {
737 : 523 : thread.running = PyThread_allocate_lock();
738 [ - + ]: 523 : if (!thread.running) {
739 : : return PyErr_NoMemory();
740 : : }
741 : : }
742 [ + + ]: 602 : if (!thread.cancel_event) {
743 : 523 : thread.cancel_event = PyThread_allocate_lock();
744 [ + - - + ]: 523 : if (!thread.cancel_event || !thread.running) {
745 : : return PyErr_NoMemory();
746 : : }
747 : :
748 : : /* cancel_event starts to be acquired: it's only released to cancel
749 : : the thread. */
750 : 523 : PyThread_acquire_lock(thread.cancel_event, 1);
751 : : }
752 : :
753 : : /* format the timeout */
754 : 602 : header = format_timeout(timeout_us);
755 [ - + ]: 602 : if (header == NULL) {
756 : : return PyErr_NoMemory();
757 : : }
758 : 602 : header_len = strlen(header);
759 : :
760 : : /* Cancel previous thread, if running */
761 : 602 : cancel_dump_traceback_later();
762 : :
763 : 602 : Py_XINCREF(file);
764 : 602 : Py_XSETREF(thread.file, file);
765 : 602 : thread.fd = fd;
766 : : /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
767 : 602 : thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
768 : 602 : thread.repeat = repeat;
769 : 602 : thread.interp = PyThreadState_GetInterpreter(tstate);
770 : 602 : thread.exit = exit;
771 : 602 : thread.header = header;
772 : 602 : thread.header_len = header_len;
773 : :
774 : : /* Arm these locks to serve as events when released */
775 : 602 : PyThread_acquire_lock(thread.running, 1);
776 : :
777 [ - + ]: 602 : if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
778 : 0 : PyThread_release_lock(thread.running);
779 [ # # ]: 0 : Py_CLEAR(thread.file);
780 : 0 : PyMem_Free(header);
781 : 0 : thread.header = NULL;
782 : 0 : PyErr_SetString(PyExc_RuntimeError,
783 : : "unable to start watchdog thread");
784 : 0 : return NULL;
785 : : }
786 : :
787 : 602 : Py_RETURN_NONE;
788 : : }
789 : :
790 : : static PyObject*
791 : 67 : faulthandler_cancel_dump_traceback_later_py(PyObject *self,
792 : : PyObject *Py_UNUSED(ignored))
793 : : {
794 : 67 : cancel_dump_traceback_later();
795 : 67 : Py_RETURN_NONE;
796 : : }
797 : :
798 : :
799 : : #ifdef FAULTHANDLER_USER
800 : : static int
801 : 1038 : faulthandler_register(int signum, int chain, _Py_sighandler_t *previous_p)
802 : : {
803 : : #ifdef HAVE_SIGACTION
804 : : struct sigaction action;
805 : 1038 : action.sa_handler = faulthandler_user;
806 : 1038 : 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 : 1038 : action.sa_flags = SA_RESTART;
811 [ + + ]: 1038 : if (chain) {
812 : : /* do not prevent the signal from being received from within its
813 : : own signal handler */
814 : 1034 : 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 : 1038 : action.sa_flags |= SA_ONSTACK;
821 : : #endif
822 : 1038 : 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 : 5 : faulthandler_user(int signum)
842 : : {
843 : : user_signal_t *user;
844 : 5 : int save_errno = errno;
845 : :
846 : 5 : user = &user_signals[signum];
847 [ - + ]: 5 : if (!user->enabled)
848 : 0 : return;
849 : :
850 : 5 : faulthandler_dump_traceback(user->fd, user->all_threads, user->interp);
851 : :
852 : : #ifdef HAVE_SIGACTION
853 [ + + ]: 5 : if (user->chain) {
854 : 1 : (void)sigaction(signum, &user->previous, NULL);
855 : 1 : errno = save_errno;
856 : :
857 : : /* call the previous signal handler */
858 : 1 : raise(signum);
859 : :
860 : 1 : save_errno = errno;
861 : 1 : (void)faulthandler_register(signum, user->chain, NULL);
862 : 1 : 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 : 1038 : check_signum(int signum)
875 : : {
876 [ + + ]: 6228 : for (size_t i=0; i < faulthandler_nsignals; i++) {
877 [ - + ]: 5190 : if (faulthandler_handlers[i].signum == signum) {
878 : 0 : PyErr_Format(PyExc_RuntimeError,
879 : : "signal %i cannot be registered, "
880 : : "use enable() instead",
881 : : signum);
882 : 0 : return 0;
883 : : }
884 : : }
885 [ + - - + ]: 1038 : if (signum < 1 || Py_NSIG <= signum) {
886 : 0 : PyErr_SetString(PyExc_ValueError, "signal number out of range");
887 : 0 : return 0;
888 : : }
889 : 1038 : return 1;
890 : : }
891 : :
892 : : static PyObject*
893 : 1038 : 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 : 1038 : PyObject *file = NULL;
899 : 1038 : int all_threads = 1;
900 : 1038 : int chain = 0;
901 : : int fd;
902 : : user_signal_t *user;
903 : : _Py_sighandler_t previous;
904 : : PyThreadState *tstate;
905 : : int err;
906 : :
907 [ - + ]: 1038 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
908 : : "i|Oii:register", kwlist,
909 : : &signum, &file, &all_threads, &chain))
910 : 0 : return NULL;
911 : :
912 [ - + ]: 1038 : if (!check_signum(signum))
913 : 0 : return NULL;
914 : :
915 : 1038 : tstate = get_thread_state();
916 [ - + ]: 1038 : if (tstate == NULL)
917 : 0 : return NULL;
918 : :
919 : 1038 : fd = faulthandler_get_fileno(&file);
920 [ + + ]: 1038 : if (fd < 0)
921 : 1 : return NULL;
922 : :
923 [ + + ]: 1037 : if (user_signals == NULL) {
924 : 521 : user_signals = PyMem_Calloc(Py_NSIG, sizeof(user_signal_t));
925 [ - + ]: 521 : if (user_signals == NULL)
926 : : return PyErr_NoMemory();
927 : : }
928 : 1037 : user = &user_signals[signum];
929 : :
930 [ + - ]: 1037 : if (!user->enabled) {
931 : : #ifdef FAULTHANDLER_USE_ALT_STACK
932 [ - + ]: 1037 : if (faulthandler_allocate_stack() < 0) {
933 : 0 : return NULL;
934 : : }
935 : : #endif
936 : :
937 : 1037 : err = faulthandler_register(signum, chain, &previous);
938 [ - + ]: 1037 : if (err) {
939 : 0 : PyErr_SetFromErrno(PyExc_OSError);
940 : 0 : return NULL;
941 : : }
942 : :
943 : 1037 : user->previous = previous;
944 : : }
945 : :
946 : 1037 : Py_XINCREF(file);
947 : 1037 : Py_XSETREF(user->file, file);
948 : 1037 : user->fd = fd;
949 : 1037 : user->all_threads = all_threads;
950 : 1037 : user->chain = chain;
951 : 1037 : user->interp = PyThreadState_GetInterpreter(tstate);
952 : 1037 : user->enabled = 1;
953 : :
954 : 1037 : Py_RETURN_NONE;
955 : : }
956 : :
957 : : static int
958 : 33865 : faulthandler_unregister(user_signal_t *user, int signum)
959 : : {
960 [ + + ]: 33865 : if (!user->enabled)
961 : 32828 : return 0;
962 : 1037 : user->enabled = 0;
963 : : #ifdef HAVE_SIGACTION
964 : 1037 : (void)sigaction(signum, &user->previous, NULL);
965 : : #else
966 : : (void)signal(signum, user->previous);
967 : : #endif
968 [ + + ]: 1037 : Py_CLEAR(user->file);
969 : 1037 : user->fd = -1;
970 : 1037 : return 1;
971 : : }
972 : :
973 : : static PyObject*
974 : 0 : faulthandler_unregister_py(PyObject *self, PyObject *args)
975 : : {
976 : : int signum;
977 : : user_signal_t *user;
978 : : int change;
979 : :
980 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "i:unregister", &signum))
981 : 0 : return NULL;
982 : :
983 [ # # ]: 0 : if (!check_signum(signum))
984 : 0 : return NULL;
985 : :
986 [ # # ]: 0 : if (user_signals == NULL)
987 : 0 : Py_RETURN_FALSE;
988 : :
989 : 0 : user = &user_signals[signum];
990 : 0 : change = faulthandler_unregister(user, signum);
991 : 0 : return PyBool_FromLong(change);
992 : : }
993 : : #endif /* FAULTHANDLER_USER */
994 : :
995 : :
996 : : static void
997 : 0 : 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 [ # # ]: 0 : if (getrlimit(RLIMIT_CORE, &rl) == 0) {
1012 : 0 : rl.rlim_cur = 0;
1013 : 0 : 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 : 0 : }
1023 : :
1024 : : static PyObject* _Py_NO_SANITIZE_UNDEFINED
1025 : 0 : faulthandler_read_null(PyObject *self, PyObject *args)
1026 : : {
1027 : : volatile int *x;
1028 : : volatile int y;
1029 : :
1030 : 0 : faulthandler_suppress_crash_report();
1031 : 0 : x = NULL;
1032 : 0 : y = *x;
1033 : 0 : return PyLong_FromLong(y);
1034 : :
1035 : : }
1036 : :
1037 : : static void
1038 : 0 : faulthandler_raise_sigsegv(void)
1039 : : {
1040 : 0 : 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 : 0 : raise(SIGSEGV);
1057 : : #endif
1058 : 0 : }
1059 : :
1060 : : static PyObject *
1061 : 0 : faulthandler_sigsegv(PyObject *self, PyObject *args)
1062 : : {
1063 : 0 : int release_gil = 0;
1064 [ # # ]: 0 : if (!PyArg_ParseTuple(args, "|i:_sigsegv", &release_gil))
1065 : 0 : return NULL;
1066 : :
1067 [ # # ]: 0 : if (release_gil) {
1068 : 0 : Py_BEGIN_ALLOW_THREADS
1069 : 0 : faulthandler_raise_sigsegv();
1070 : 0 : Py_END_ALLOW_THREADS
1071 : : } else {
1072 : 0 : faulthandler_raise_sigsegv();
1073 : : }
1074 : 0 : Py_RETURN_NONE;
1075 : : }
1076 : :
1077 : : static void _Py_NO_RETURN
1078 : 0 : faulthandler_fatal_error_thread(void *plock)
1079 : : {
1080 : : Py_FatalError("in new thread");
1081 : : }
1082 : :
1083 : : static PyObject *
1084 : 0 : faulthandler_fatal_error_c_thread(PyObject *self, PyObject *args)
1085 : : {
1086 : : long thread;
1087 : : PyThread_type_lock lock;
1088 : :
1089 : 0 : faulthandler_suppress_crash_report();
1090 : :
1091 : 0 : lock = PyThread_allocate_lock();
1092 [ # # ]: 0 : if (lock == NULL)
1093 : : return PyErr_NoMemory();
1094 : :
1095 : 0 : PyThread_acquire_lock(lock, WAIT_LOCK);
1096 : :
1097 : 0 : thread = PyThread_start_new_thread(faulthandler_fatal_error_thread, lock);
1098 [ # # ]: 0 : if (thread == -1) {
1099 : 0 : PyThread_free_lock(lock);
1100 : 0 : PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
1101 : 0 : return NULL;
1102 : : }
1103 : :
1104 : : /* wait until the thread completes: it will never occur, since Py_FatalError()
1105 : : exits the process immediately. */
1106 : 0 : PyThread_acquire_lock(lock, WAIT_LOCK);
1107 : 0 : PyThread_release_lock(lock);
1108 : 0 : PyThread_free_lock(lock);
1109 : :
1110 : 0 : Py_RETURN_NONE;
1111 : : }
1112 : :
1113 : : static PyObject* _Py_NO_SANITIZE_UNDEFINED
1114 : 0 : faulthandler_sigfpe(PyObject *self, PyObject *args)
1115 : : {
1116 : 0 : 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 : 0 : volatile int x = 1, y = 0, z;
1121 : 0 : z = x / y;
1122 : :
1123 : : /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
1124 : : raise it manually. */
1125 : 0 : raise(SIGFPE);
1126 : :
1127 : : /* This line is never reached, but we pretend to make something with z
1128 : : to silence a compiler warning. */
1129 : 0 : return PyLong_FromLong(z);
1130 : : }
1131 : :
1132 : : static PyObject *
1133 : 0 : faulthandler_sigabrt(PyObject *self, PyObject *args)
1134 : : {
1135 : 0 : faulthandler_suppress_crash_report();
1136 : 0 : 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 : 0 : 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 : 0 : uintptr_t sp = (uintptr_t)&buffer;
1152 : 0 : *depth += 1;
1153 [ # # # # ]: 0 : if (sp < min_sp || max_sp < sp)
1154 : 0 : return sp;
1155 : 0 : buffer[0] = 1;
1156 : 0 : buffer[4095] = 0;
1157 : 0 : return stack_overflow(min_sp, max_sp, depth);
1158 : : }
1159 : :
1160 : : static PyObject *
1161 : 0 : faulthandler_stack_overflow(PyObject *self, PyObject *Py_UNUSED(ignored))
1162 : : {
1163 : : size_t depth, size;
1164 : 0 : uintptr_t sp = (uintptr_t)&depth;
1165 : : uintptr_t stop, lower_limit, upper_limit;
1166 : :
1167 : 0 : faulthandler_suppress_crash_report();
1168 : 0 : depth = 0;
1169 : :
1170 [ # # ]: 0 : if (STACK_OVERFLOW_MAX_SIZE <= sp) {
1171 : 0 : lower_limit = sp - STACK_OVERFLOW_MAX_SIZE;
1172 : : }
1173 : : else {
1174 : 0 : lower_limit = 0;
1175 : : }
1176 : :
1177 [ # # ]: 0 : if (UINTPTR_MAX - STACK_OVERFLOW_MAX_SIZE >= sp) {
1178 : 0 : upper_limit = sp + STACK_OVERFLOW_MAX_SIZE;
1179 : : }
1180 : : else {
1181 : 0 : upper_limit = UINTPTR_MAX;
1182 : : }
1183 : :
1184 : 0 : stop = stack_overflow(lower_limit, upper_limit, &depth);
1185 [ # # ]: 0 : if (sp < stop)
1186 : 0 : size = stop - sp;
1187 : : else
1188 : 0 : size = sp - stop;
1189 : 0 : 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 : 0 : return NULL;
1194 : : }
1195 : : #endif /* defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_SIGACTION) */
1196 : :
1197 : :
1198 : : static int
1199 : 45215 : faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
1200 : : {
1201 [ + + - + ]: 45215 : Py_VISIT(thread.file);
1202 : : #ifdef FAULTHANDLER_USER
1203 [ + + ]: 45215 : if (user_signals != NULL) {
1204 [ + + ]: 2103024 : for (size_t signum=0; signum < Py_NSIG; signum++)
1205 [ + + - + ]: 2071160 : Py_VISIT(user_signals[signum].file);
1206 : : }
1207 : : #endif
1208 [ + + - + ]: 45215 : Py_VISIT(fatal_error.file);
1209 : 45215 : 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 : 1992 : 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 : 1992 : 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 : 1992 : PyInit_faulthandler(void)
1334 : : {
1335 : 1992 : return PyModuleDef_Init(&module_def);
1336 : : }
1337 : :
1338 : : static int
1339 : 1094 : faulthandler_init_enable(void)
1340 : : {
1341 : 1094 : PyObject *enable = _PyImport_GetModuleAttrString("faulthandler", "enable");
1342 [ - + ]: 1094 : if (enable == NULL) {
1343 : 0 : return -1;
1344 : : }
1345 : :
1346 : 1094 : PyObject *res = PyObject_CallNoArgs(enable);
1347 : 1094 : Py_DECREF(enable);
1348 [ - + ]: 1094 : if (res == NULL) {
1349 : 0 : return -1;
1350 : : }
1351 : 1094 : Py_DECREF(res);
1352 : :
1353 : 1094 : return 0;
1354 : : }
1355 : :
1356 : : PyStatus
1357 : 2963 : _PyFaulthandler_Init(int enable)
1358 : : {
1359 : : #ifdef FAULTHANDLER_USE_ALT_STACK
1360 : 2963 : memset(&stack, 0, sizeof(stack));
1361 : 2963 : 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 : 2963 : 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 : 2963 : unsigned long at_minstack_size = getauxval(AT_MINSIGSTKSZ);
1372 [ + - ]: 2963 : if (at_minstack_size != 0) {
1373 : 2963 : stack.ss_size = SIGSTKSZ + at_minstack_size;
1374 : : }
1375 : : #endif
1376 : : #endif
1377 : :
1378 : 2963 : memset(&thread, 0, sizeof(thread));
1379 : :
1380 [ + + ]: 2963 : if (enable) {
1381 [ - + ]: 1094 : if (faulthandler_init_enable() < 0) {
1382 : 0 : return _PyStatus_ERR("failed to enable faulthandler");
1383 : : }
1384 : : }
1385 : 2963 : return _PyStatus_OK();
1386 : : }
1387 : :
1388 : 2963 : void _PyFaulthandler_Fini(void)
1389 : : {
1390 : : /* later */
1391 [ + + ]: 2963 : if (thread.cancel_event) {
1392 : 523 : cancel_dump_traceback_later();
1393 : 523 : PyThread_release_lock(thread.cancel_event);
1394 : 523 : PyThread_free_lock(thread.cancel_event);
1395 : 523 : thread.cancel_event = NULL;
1396 : : }
1397 [ + + ]: 2963 : if (thread.running) {
1398 : 523 : PyThread_free_lock(thread.running);
1399 : 523 : thread.running = NULL;
1400 : : }
1401 : :
1402 : : #ifdef FAULTHANDLER_USER
1403 : : /* user */
1404 [ + + ]: 2963 : if (user_signals != NULL) {
1405 [ + + ]: 34386 : for (size_t signum=0; signum < Py_NSIG; signum++) {
1406 : 33865 : faulthandler_unregister(&user_signals[signum], signum);
1407 : : }
1408 : 521 : PyMem_Free(user_signals);
1409 : 521 : user_signals = NULL;
1410 : : }
1411 : : #endif
1412 : :
1413 : : /* fatal */
1414 : 2963 : faulthandler_disable();
1415 : :
1416 : : #ifdef FAULTHANDLER_USE_ALT_STACK
1417 [ + + ]: 2963 : if (stack.ss_sp != NULL) {
1418 : : /* Fetch the current alt stack */
1419 : : stack_t current_stack;
1420 : 1534 : memset(¤t_stack, 0, sizeof(current_stack));
1421 [ + - ]: 1534 : if (sigaltstack(NULL, ¤t_stack) == 0) {
1422 [ + - ]: 1534 : if (current_stack.ss_sp == stack.ss_sp) {
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 : 1534 : 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 : 1534 : PyMem_Free(stack.ss_sp);
1434 : 1534 : stack.ss_sp = NULL;
1435 : : }
1436 : : #endif
1437 : 2963 : }
|