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