Line data Source code
1 : #include "Python.h"
2 : #include "pythread.h"
3 : #include <signal.h>
4 : #include <object.h>
5 : #include <frameobject.h>
6 : #include <signal.h>
7 : #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
8 : #include <pthread.h>
9 : #endif
10 :
11 : /* Allocate at maximum 100 MB of the stack to raise the stack overflow */
12 : #define STACK_OVERFLOW_MAX_SIZE (100*1024*1024)
13 :
14 : #ifdef WITH_THREAD
15 : # define FAULTHANDLER_LATER
16 : #endif
17 :
18 : #ifndef MS_WINDOWS
19 : /* register() is useless on Windows, because only SIGSEGV, SIGABRT and
20 : SIGILL can be handled by the process, and these signals can only be used
21 : with enable(), not using register() */
22 : # define FAULTHANDLER_USER
23 : #endif
24 :
25 : #define PUTS(fd, str) write(fd, str, strlen(str))
26 :
27 : #ifdef HAVE_SIGACTION
28 : typedef struct sigaction _Py_sighandler_t;
29 : #else
30 : typedef PyOS_sighandler_t _Py_sighandler_t;
31 : #endif
32 :
33 : typedef struct {
34 : int signum;
35 : int enabled;
36 : const char* name;
37 : _Py_sighandler_t previous;
38 : int all_threads;
39 : } fault_handler_t;
40 :
41 : static struct {
42 : int enabled;
43 : PyObject *file;
44 : int fd;
45 : int all_threads;
46 : PyInterpreterState *interp;
47 : } fatal_error = {0, NULL, -1, 0};
48 :
49 : #ifdef FAULTHANDLER_LATER
50 : static struct {
51 : PyObject *file;
52 : int fd;
53 : PY_TIMEOUT_T timeout_us; /* timeout in microseconds */
54 : int repeat;
55 : PyInterpreterState *interp;
56 : int exit;
57 : char *header;
58 : size_t header_len;
59 : /* The main thread always holds this lock. It is only released when
60 : faulthandler_thread() is interrupted before this thread exits, or at
61 : Python exit. */
62 : PyThread_type_lock cancel_event;
63 : /* released by child thread when joined */
64 : PyThread_type_lock running;
65 : } thread;
66 : #endif
67 :
68 : #ifdef FAULTHANDLER_USER
69 : typedef struct {
70 : int enabled;
71 : PyObject *file;
72 : int fd;
73 : int all_threads;
74 : int chain;
75 : _Py_sighandler_t previous;
76 : PyInterpreterState *interp;
77 : } user_signal_t;
78 :
79 : static user_signal_t *user_signals;
80 :
81 : /* the following macros come from Python: Modules/signalmodule.c */
82 : #if defined(PYOS_OS2) && !defined(PYCC_GCC)
83 : #define NSIG 12
84 : #endif
85 : #ifndef NSIG
86 : # if defined(_NSIG)
87 : # define NSIG _NSIG /* For BSD/SysV */
88 : # elif defined(_SIGMAX)
89 : # define NSIG (_SIGMAX + 1) /* For QNX */
90 : # elif defined(SIGMAX)
91 : # define NSIG (SIGMAX + 1) /* For djgpp */
92 : # else
93 : # define NSIG 64 /* Use a reasonable default value */
94 : # endif
95 : #endif
96 :
97 : static void faulthandler_user(int signum);
98 : #endif /* FAULTHANDLER_USER */
99 :
100 :
101 : static fault_handler_t faulthandler_handlers[] = {
102 : #ifdef SIGBUS
103 : {SIGBUS, 0, "Bus error", },
104 : #endif
105 : #ifdef SIGILL
106 : {SIGILL, 0, "Illegal instruction", },
107 : #endif
108 : {SIGFPE, 0, "Floating point exception", },
109 : {SIGABRT, 0, "Aborted", },
110 : /* define SIGSEGV at the end to make it the default choice if searching the
111 : handler fails in faulthandler_fatal_error() */
112 : {SIGSEGV, 0, "Segmentation fault", }
113 : };
114 : static const unsigned char faulthandler_nsignals = \
115 : Py_ARRAY_LENGTH(faulthandler_handlers);
116 :
117 : #ifdef HAVE_SIGALTSTACK
118 : static stack_t stack;
119 : #endif
120 :
121 :
122 : /* Get the file descriptor of a file by calling its fileno() method and then
123 : call its flush() method.
124 :
125 : If file is NULL or Py_None, use sys.stderr as the new file.
126 :
127 : On success, return the new file and write the file descriptor into *p_fd.
128 : On error, return NULL. */
129 :
130 : static PyObject*
131 0 : faulthandler_get_fileno(PyObject *file, int *p_fd)
132 : {
133 : PyObject *result;
134 : _Py_IDENTIFIER(fileno);
135 : _Py_IDENTIFIER(flush);
136 : long fd_long;
137 : int fd;
138 :
139 0 : if (file == NULL || file == Py_None) {
140 0 : file = PySys_GetObject("stderr");
141 0 : if (file == NULL) {
142 0 : PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr");
143 0 : return NULL;
144 : }
145 : }
146 :
147 0 : result = _PyObject_CallMethodId(file, &PyId_fileno, "");
148 0 : if (result == NULL)
149 0 : return NULL;
150 :
151 0 : fd = -1;
152 0 : if (PyLong_Check(result)) {
153 0 : fd_long = PyLong_AsLong(result);
154 0 : if (0 <= fd_long && fd_long < INT_MAX)
155 0 : fd = (int)fd_long;
156 : }
157 0 : Py_DECREF(result);
158 :
159 0 : if (fd == -1) {
160 0 : PyErr_SetString(PyExc_RuntimeError,
161 : "file.fileno() is not a valid file descriptor");
162 0 : return NULL;
163 : }
164 :
165 0 : result = _PyObject_CallMethodId(file, &PyId_flush, "");
166 0 : if (result != NULL)
167 0 : Py_DECREF(result);
168 : else {
169 : /* ignore flush() error */
170 0 : PyErr_Clear();
171 : }
172 0 : *p_fd = fd;
173 0 : return file;
174 : }
175 :
176 : /* Get the state of the current thread: only call this function if the current
177 : thread holds the GIL. Raise an exception on error. */
178 : static PyThreadState*
179 0 : get_thread_state(void)
180 : {
181 0 : PyThreadState *tstate = PyThreadState_Get();
182 0 : if (tstate == NULL) {
183 0 : PyErr_SetString(PyExc_RuntimeError,
184 : "unable to get the current thread state");
185 0 : return NULL;
186 : }
187 0 : return tstate;
188 : }
189 :
190 : static PyObject*
191 0 : faulthandler_dump_traceback_py(PyObject *self,
192 : PyObject *args, PyObject *kwargs)
193 : {
194 : static char *kwlist[] = {"file", "all_threads", NULL};
195 0 : PyObject *file = NULL;
196 0 : int all_threads = 1;
197 : PyThreadState *tstate;
198 : const char *errmsg;
199 : int fd;
200 :
201 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
202 : "|Oi:dump_traceback", kwlist,
203 : &file, &all_threads))
204 0 : return NULL;
205 :
206 0 : file = faulthandler_get_fileno(file, &fd);
207 0 : if (file == NULL)
208 0 : return NULL;
209 :
210 0 : tstate = get_thread_state();
211 0 : if (tstate == NULL)
212 0 : return NULL;
213 :
214 0 : if (all_threads) {
215 0 : errmsg = _Py_DumpTracebackThreads(fd, tstate->interp, tstate);
216 0 : if (errmsg != NULL) {
217 0 : PyErr_SetString(PyExc_RuntimeError, errmsg);
218 0 : return NULL;
219 : }
220 : }
221 : else {
222 0 : _Py_DumpTraceback(fd, tstate);
223 : }
224 0 : Py_RETURN_NONE;
225 : }
226 :
227 :
228 : /* Handler for SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL signals.
229 :
230 : Display the current Python traceback, restore the previous handler and call
231 : the previous handler.
232 :
233 : On Windows, don't explicitly call the previous handler, because the Windows
234 : signal handler would not be called (for an unknown reason). The execution of
235 : the program continues at faulthandler_fatal_error() exit, but the same
236 : instruction will raise the same fault (signal), and so the previous handler
237 : will be called.
238 :
239 : This function is signal-safe and should only call signal-safe functions. */
240 :
241 : static void
242 0 : faulthandler_fatal_error(int signum)
243 : {
244 0 : const int fd = fatal_error.fd;
245 : unsigned int i;
246 0 : fault_handler_t *handler = NULL;
247 : PyThreadState *tstate;
248 0 : int save_errno = errno;
249 :
250 0 : if (!fatal_error.enabled)
251 0 : return;
252 :
253 0 : for (i=0; i < faulthandler_nsignals; i++) {
254 0 : handler = &faulthandler_handlers[i];
255 0 : if (handler->signum == signum)
256 0 : break;
257 : }
258 0 : if (handler == NULL) {
259 : /* faulthandler_nsignals == 0 (unlikely) */
260 0 : return;
261 : }
262 :
263 : /* restore the previous handler */
264 : #ifdef HAVE_SIGACTION
265 0 : (void)sigaction(signum, &handler->previous, NULL);
266 : #else
267 : (void)signal(signum, handler->previous);
268 : #endif
269 0 : handler->enabled = 0;
270 :
271 0 : PUTS(fd, "Fatal Python error: ");
272 0 : PUTS(fd, handler->name);
273 0 : PUTS(fd, "\n\n");
274 :
275 : #ifdef WITH_THREAD
276 : /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and
277 : are thus delivered to the thread that caused the fault. Get the Python
278 : thread state of the current thread.
279 :
280 : PyThreadState_Get() doesn't give the state of the thread that caused the
281 : fault if the thread released the GIL, and so this function cannot be
282 : used. Read the thread local storage (TLS) instead: call
283 : PyGILState_GetThisThreadState(). */
284 0 : tstate = PyGILState_GetThisThreadState();
285 : #else
286 : tstate = PyThreadState_Get();
287 : #endif
288 :
289 0 : if (fatal_error.all_threads)
290 0 : _Py_DumpTracebackThreads(fd, fatal_error.interp, tstate);
291 : else {
292 0 : if (tstate != NULL)
293 0 : _Py_DumpTraceback(fd, tstate);
294 : }
295 :
296 0 : errno = save_errno;
297 : #ifdef MS_WINDOWS
298 : if (signum == SIGSEGV) {
299 : /* don't explicitly call the previous handler for SIGSEGV in this signal
300 : handler, because the Windows signal handler would not be called */
301 : return;
302 : }
303 : #endif
304 : /* call the previous signal handler: it is called immediatly if we use
305 : sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */
306 0 : raise(signum);
307 : }
308 :
309 : /* Install the handler for fatal signals, faulthandler_fatal_error(). */
310 :
311 : static PyObject*
312 0 : faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs)
313 : {
314 : static char *kwlist[] = {"file", "all_threads", NULL};
315 0 : PyObject *file = NULL;
316 0 : int all_threads = 1;
317 : unsigned int i;
318 : fault_handler_t *handler;
319 : #ifdef HAVE_SIGACTION
320 : struct sigaction action;
321 : #endif
322 : int err;
323 : int fd;
324 : PyThreadState *tstate;
325 :
326 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
327 : "|Oi:enable", kwlist, &file, &all_threads))
328 0 : return NULL;
329 :
330 0 : file = faulthandler_get_fileno(file, &fd);
331 0 : if (file == NULL)
332 0 : return NULL;
333 :
334 0 : tstate = get_thread_state();
335 0 : if (tstate == NULL)
336 0 : return NULL;
337 :
338 0 : Py_XDECREF(fatal_error.file);
339 0 : Py_INCREF(file);
340 0 : fatal_error.file = file;
341 0 : fatal_error.fd = fd;
342 0 : fatal_error.all_threads = all_threads;
343 0 : fatal_error.interp = tstate->interp;
344 :
345 0 : if (!fatal_error.enabled) {
346 0 : fatal_error.enabled = 1;
347 :
348 0 : for (i=0; i < faulthandler_nsignals; i++) {
349 0 : handler = &faulthandler_handlers[i];
350 : #ifdef HAVE_SIGACTION
351 0 : action.sa_handler = faulthandler_fatal_error;
352 0 : sigemptyset(&action.sa_mask);
353 : /* Do not prevent the signal from being received from within
354 : its own signal handler */
355 0 : action.sa_flags = SA_NODEFER;
356 : #ifdef HAVE_SIGALTSTACK
357 0 : if (stack.ss_sp != NULL) {
358 : /* Call the signal handler on an alternate signal stack
359 : provided by sigaltstack() */
360 0 : action.sa_flags |= SA_ONSTACK;
361 : }
362 : #endif
363 0 : err = sigaction(handler->signum, &action, &handler->previous);
364 : #else
365 : handler->previous = signal(handler->signum,
366 : faulthandler_fatal_error);
367 : err = (handler->previous == SIG_ERR);
368 : #endif
369 0 : if (err) {
370 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
371 0 : return NULL;
372 : }
373 0 : handler->enabled = 1;
374 : }
375 : }
376 0 : Py_RETURN_NONE;
377 : }
378 :
379 : static void
380 0 : faulthandler_disable(void)
381 : {
382 : unsigned int i;
383 : fault_handler_t *handler;
384 :
385 0 : if (fatal_error.enabled) {
386 0 : fatal_error.enabled = 0;
387 0 : for (i=0; i < faulthandler_nsignals; i++) {
388 0 : handler = &faulthandler_handlers[i];
389 0 : if (!handler->enabled)
390 0 : continue;
391 : #ifdef HAVE_SIGACTION
392 0 : (void)sigaction(handler->signum, &handler->previous, NULL);
393 : #else
394 : (void)signal(handler->signum, handler->previous);
395 : #endif
396 0 : handler->enabled = 0;
397 : }
398 : }
399 :
400 0 : Py_CLEAR(fatal_error.file);
401 0 : }
402 :
403 : static PyObject*
404 0 : faulthandler_disable_py(PyObject *self)
405 : {
406 0 : if (!fatal_error.enabled) {
407 0 : Py_INCREF(Py_False);
408 0 : return Py_False;
409 : }
410 0 : faulthandler_disable();
411 0 : Py_INCREF(Py_True);
412 0 : return Py_True;
413 : }
414 :
415 : static PyObject*
416 0 : faulthandler_is_enabled(PyObject *self)
417 : {
418 0 : return PyBool_FromLong(fatal_error.enabled);
419 : }
420 :
421 : #ifdef FAULTHANDLER_LATER
422 :
423 : static void
424 0 : faulthandler_thread(void *unused)
425 : {
426 : PyLockStatus st;
427 : const char* errmsg;
428 : PyThreadState *current;
429 : int ok;
430 : #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
431 : sigset_t set;
432 :
433 : /* we don't want to receive any signal */
434 0 : sigfillset(&set);
435 0 : pthread_sigmask(SIG_SETMASK, &set, NULL);
436 : #endif
437 :
438 : do {
439 0 : st = PyThread_acquire_lock_timed(thread.cancel_event,
440 : thread.timeout_us, 0);
441 0 : if (st == PY_LOCK_ACQUIRED) {
442 0 : PyThread_release_lock(thread.cancel_event);
443 0 : break;
444 : }
445 : /* Timeout => dump traceback */
446 : assert(st == PY_LOCK_FAILURE);
447 :
448 : /* get the thread holding the GIL, NULL if no thread hold the GIL */
449 0 : current = _Py_atomic_load_relaxed(&_PyThreadState_Current);
450 :
451 0 : write(thread.fd, thread.header, thread.header_len);
452 :
453 0 : errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current);
454 0 : ok = (errmsg == NULL);
455 :
456 0 : if (thread.exit)
457 0 : _exit(1);
458 0 : } while (ok && thread.repeat);
459 :
460 : /* The only way out */
461 0 : PyThread_release_lock(thread.running);
462 0 : }
463 :
464 : static void
465 0 : cancel_dump_traceback_later(void)
466 : {
467 : /* Notify cancellation */
468 0 : PyThread_release_lock(thread.cancel_event);
469 :
470 : /* Wait for thread to join */
471 0 : PyThread_acquire_lock(thread.running, 1);
472 0 : PyThread_release_lock(thread.running);
473 :
474 : /* The main thread should always hold the cancel_event lock */
475 0 : PyThread_acquire_lock(thread.cancel_event, 1);
476 :
477 0 : Py_CLEAR(thread.file);
478 0 : if (thread.header) {
479 0 : free(thread.header);
480 0 : thread.header = NULL;
481 : }
482 0 : }
483 :
484 : static char*
485 0 : format_timeout(double timeout)
486 : {
487 : unsigned long us, sec, min, hour;
488 : double intpart, fracpart;
489 : char buffer[100];
490 :
491 0 : fracpart = modf(timeout, &intpart);
492 0 : sec = (unsigned long)intpart;
493 0 : us = (unsigned long)(fracpart * 1e6);
494 0 : min = sec / 60;
495 0 : sec %= 60;
496 0 : hour = min / 60;
497 0 : min %= 60;
498 :
499 0 : if (us != 0)
500 0 : PyOS_snprintf(buffer, sizeof(buffer),
501 : "Timeout (%lu:%02lu:%02lu.%06lu)!\n",
502 : hour, min, sec, us);
503 : else
504 0 : PyOS_snprintf(buffer, sizeof(buffer),
505 : "Timeout (%lu:%02lu:%02lu)!\n",
506 : hour, min, sec);
507 :
508 0 : return strdup(buffer);
509 : }
510 :
511 : static PyObject*
512 0 : faulthandler_dump_traceback_later(PyObject *self,
513 : PyObject *args, PyObject *kwargs)
514 : {
515 : static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
516 : double timeout;
517 : PY_TIMEOUT_T timeout_us;
518 0 : int repeat = 0;
519 0 : PyObject *file = NULL;
520 : int fd;
521 0 : int exit = 0;
522 : PyThreadState *tstate;
523 : char *header;
524 : size_t header_len;
525 :
526 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
527 : "d|iOi:dump_traceback_later", kwlist,
528 : &timeout, &repeat, &file, &exit))
529 0 : return NULL;
530 0 : if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) {
531 0 : PyErr_SetString(PyExc_OverflowError, "timeout value is too large");
532 0 : return NULL;
533 : }
534 0 : timeout_us = (PY_TIMEOUT_T)(timeout * 1e6);
535 0 : if (timeout_us <= 0) {
536 0 : PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
537 0 : return NULL;
538 : }
539 :
540 0 : tstate = get_thread_state();
541 0 : if (tstate == NULL)
542 0 : return NULL;
543 :
544 0 : file = faulthandler_get_fileno(file, &fd);
545 0 : if (file == NULL)
546 0 : return NULL;
547 :
548 : /* format the timeout */
549 0 : header = format_timeout(timeout);
550 0 : if (header == NULL)
551 0 : return PyErr_NoMemory();
552 0 : header_len = strlen(header);
553 :
554 : /* Cancel previous thread, if running */
555 0 : cancel_dump_traceback_later();
556 :
557 0 : Py_XDECREF(thread.file);
558 0 : Py_INCREF(file);
559 0 : thread.file = file;
560 0 : thread.fd = fd;
561 0 : thread.timeout_us = timeout_us;
562 0 : thread.repeat = repeat;
563 0 : thread.interp = tstate->interp;
564 0 : thread.exit = exit;
565 0 : thread.header = header;
566 0 : thread.header_len = header_len;
567 :
568 : /* Arm these locks to serve as events when released */
569 0 : PyThread_acquire_lock(thread.running, 1);
570 :
571 0 : if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) {
572 0 : PyThread_release_lock(thread.running);
573 0 : Py_CLEAR(thread.file);
574 0 : free(header);
575 0 : thread.header = NULL;
576 0 : PyErr_SetString(PyExc_RuntimeError,
577 : "unable to start watchdog thread");
578 0 : return NULL;
579 : }
580 :
581 0 : Py_RETURN_NONE;
582 : }
583 :
584 : static PyObject*
585 0 : faulthandler_cancel_dump_traceback_later_py(PyObject *self)
586 : {
587 0 : cancel_dump_traceback_later();
588 0 : Py_RETURN_NONE;
589 : }
590 : #endif /* FAULTHANDLER_LATER */
591 :
592 : #ifdef FAULTHANDLER_USER
593 : static int
594 0 : faulthandler_register(int signum, int chain, _Py_sighandler_t *p_previous)
595 : {
596 : #ifdef HAVE_SIGACTION
597 : struct sigaction action;
598 0 : action.sa_handler = faulthandler_user;
599 0 : sigemptyset(&action.sa_mask);
600 : /* if the signal is received while the kernel is executing a system
601 : call, try to restart the system call instead of interrupting it and
602 : return EINTR. */
603 0 : action.sa_flags = SA_RESTART;
604 0 : if (chain) {
605 : /* do not prevent the signal from being received from within its
606 : own signal handler */
607 0 : action.sa_flags = SA_NODEFER;
608 : }
609 : #ifdef HAVE_SIGALTSTACK
610 0 : if (stack.ss_sp != NULL) {
611 : /* Call the signal handler on an alternate signal stack
612 : provided by sigaltstack() */
613 0 : action.sa_flags |= SA_ONSTACK;
614 : }
615 : #endif
616 0 : return sigaction(signum, &action, p_previous);
617 : #else
618 : _Py_sighandler_t previous;
619 : previous = signal(signum, faulthandler_user);
620 : if (p_previous != NULL)
621 : *p_previous = previous;
622 : return (previous == SIG_ERR);
623 : #endif
624 : }
625 :
626 : /* Handler of user signals (e.g. SIGUSR1).
627 :
628 : Dump the traceback of the current thread, or of all threads if
629 : thread.all_threads is true.
630 :
631 : This function is signal safe and should only call signal safe functions. */
632 :
633 : static void
634 0 : faulthandler_user(int signum)
635 : {
636 : user_signal_t *user;
637 : PyThreadState *tstate;
638 0 : int save_errno = errno;
639 :
640 0 : user = &user_signals[signum];
641 0 : if (!user->enabled)
642 0 : return;
643 :
644 : #ifdef WITH_THREAD
645 : /* PyThreadState_Get() doesn't give the state of the current thread if
646 : the thread doesn't hold the GIL. Read the thread local storage (TLS)
647 : instead: call PyGILState_GetThisThreadState(). */
648 0 : tstate = PyGILState_GetThisThreadState();
649 : #else
650 : tstate = PyThreadState_Get();
651 : #endif
652 :
653 0 : if (user->all_threads)
654 0 : _Py_DumpTracebackThreads(user->fd, user->interp, tstate);
655 : else {
656 0 : if (tstate != NULL)
657 0 : _Py_DumpTraceback(user->fd, tstate);
658 : }
659 : #ifdef HAVE_SIGACTION
660 0 : if (user->chain) {
661 0 : (void)sigaction(signum, &user->previous, NULL);
662 0 : errno = save_errno;
663 :
664 : /* call the previous signal handler */
665 0 : raise(signum);
666 :
667 0 : save_errno = errno;
668 0 : (void)faulthandler_register(signum, user->chain, NULL);
669 0 : errno = save_errno;
670 : }
671 : #else
672 : if (user->chain) {
673 : errno = save_errno;
674 : /* call the previous signal handler */
675 : user->previous(signum);
676 : }
677 : #endif
678 : }
679 :
680 : static int
681 0 : check_signum(int signum)
682 : {
683 : unsigned int i;
684 :
685 0 : for (i=0; i < faulthandler_nsignals; i++) {
686 0 : if (faulthandler_handlers[i].signum == signum) {
687 0 : PyErr_Format(PyExc_RuntimeError,
688 : "signal %i cannot be registered, "
689 : "use enable() instead",
690 : signum);
691 0 : return 0;
692 : }
693 : }
694 0 : if (signum < 1 || NSIG <= signum) {
695 0 : PyErr_SetString(PyExc_ValueError, "signal number out of range");
696 0 : return 0;
697 : }
698 0 : return 1;
699 : }
700 :
701 : static PyObject*
702 0 : faulthandler_register_py(PyObject *self,
703 : PyObject *args, PyObject *kwargs)
704 : {
705 : static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL};
706 : int signum;
707 0 : PyObject *file = NULL;
708 0 : int all_threads = 1;
709 0 : int chain = 0;
710 : int fd;
711 : user_signal_t *user;
712 : _Py_sighandler_t previous;
713 : PyThreadState *tstate;
714 : int err;
715 :
716 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
717 : "i|Oii:register", kwlist,
718 : &signum, &file, &all_threads, &chain))
719 0 : return NULL;
720 :
721 0 : if (!check_signum(signum))
722 0 : return NULL;
723 :
724 0 : tstate = get_thread_state();
725 0 : if (tstate == NULL)
726 0 : return NULL;
727 :
728 0 : file = faulthandler_get_fileno(file, &fd);
729 0 : if (file == NULL)
730 0 : return NULL;
731 :
732 0 : if (user_signals == NULL) {
733 0 : user_signals = calloc(NSIG, sizeof(user_signal_t));
734 0 : if (user_signals == NULL)
735 0 : return PyErr_NoMemory();
736 : }
737 0 : user = &user_signals[signum];
738 :
739 0 : if (!user->enabled) {
740 0 : err = faulthandler_register(signum, chain, &previous);
741 0 : if (err) {
742 0 : PyErr_SetFromErrno(PyExc_OSError);
743 0 : return NULL;
744 : }
745 : }
746 :
747 0 : Py_XDECREF(user->file);
748 0 : Py_INCREF(file);
749 0 : user->file = file;
750 0 : user->fd = fd;
751 0 : user->all_threads = all_threads;
752 0 : user->chain = chain;
753 0 : user->previous = previous;
754 0 : user->interp = tstate->interp;
755 0 : user->enabled = 1;
756 :
757 0 : Py_RETURN_NONE;
758 : }
759 :
760 : static int
761 0 : faulthandler_unregister(user_signal_t *user, int signum)
762 : {
763 0 : if (!user->enabled)
764 0 : return 0;
765 0 : user->enabled = 0;
766 : #ifdef HAVE_SIGACTION
767 0 : (void)sigaction(signum, &user->previous, NULL);
768 : #else
769 : (void)signal(signum, user->previous);
770 : #endif
771 0 : Py_CLEAR(user->file);
772 0 : user->fd = -1;
773 0 : return 1;
774 : }
775 :
776 : static PyObject*
777 0 : faulthandler_unregister_py(PyObject *self, PyObject *args)
778 : {
779 : int signum;
780 : user_signal_t *user;
781 : int change;
782 :
783 0 : if (!PyArg_ParseTuple(args, "i:unregister", &signum))
784 0 : return NULL;
785 :
786 0 : if (!check_signum(signum))
787 0 : return NULL;
788 :
789 0 : if (user_signals == NULL)
790 0 : Py_RETURN_FALSE;
791 :
792 0 : user = &user_signals[signum];
793 0 : change = faulthandler_unregister(user, signum);
794 0 : return PyBool_FromLong(change);
795 : }
796 : #endif /* FAULTHANDLER_USER */
797 :
798 :
799 : static PyObject *
800 0 : faulthandler_read_null(PyObject *self, PyObject *args)
801 : {
802 : volatile int *x;
803 : volatile int y;
804 0 : int release_gil = 0;
805 0 : if (!PyArg_ParseTuple(args, "|i:_read_null", &release_gil))
806 0 : return NULL;
807 :
808 0 : x = NULL;
809 0 : if (release_gil) {
810 0 : Py_BEGIN_ALLOW_THREADS
811 0 : y = *x;
812 0 : Py_END_ALLOW_THREADS
813 : } else
814 0 : y = *x;
815 0 : return PyLong_FromLong(y);
816 :
817 : }
818 :
819 : static PyObject *
820 0 : faulthandler_sigsegv(PyObject *self, PyObject *args)
821 : {
822 : #if defined(MS_WINDOWS)
823 : /* For SIGSEGV, faulthandler_fatal_error() restores the previous signal
824 : handler and then gives back the execution flow to the program (without
825 : explicitly calling the previous error handler). In a normal case, the
826 : SIGSEGV was raised by the kernel because of a fault, and so if the
827 : program retries to execute the same instruction, the fault will be
828 : raised again.
829 :
830 : Here the fault is simulated by a fake SIGSEGV signal raised by the
831 : application. We have to raise SIGSEGV at lease twice: once for
832 : faulthandler_fatal_error(), and one more time for the previous signal
833 : handler. */
834 : while(1)
835 : raise(SIGSEGV);
836 : #else
837 0 : raise(SIGSEGV);
838 : #endif
839 0 : Py_RETURN_NONE;
840 : }
841 :
842 : static PyObject *
843 0 : faulthandler_sigfpe(PyObject *self, PyObject *args)
844 : {
845 : /* Do an integer division by zero: raise a SIGFPE on Intel CPU, but not on
846 : PowerPC. Use volatile to disable compile-time optimizations. */
847 0 : volatile int x = 1, y = 0, z;
848 0 : z = x / y;
849 : /* If the division by zero didn't raise a SIGFPE (e.g. on PowerPC),
850 : raise it manually. */
851 0 : raise(SIGFPE);
852 : /* This line is never reached, but we pretend to make something with z
853 : to silence a compiler warning. */
854 0 : return PyLong_FromLong(z);
855 : }
856 :
857 : static PyObject *
858 0 : faulthandler_sigabrt(PyObject *self, PyObject *args)
859 : {
860 : #ifdef _MSC_VER
861 : /* Visual Studio: configure abort() to not display an error message nor
862 : open a popup asking to report the fault. */
863 : _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
864 : #endif
865 0 : abort();
866 : Py_RETURN_NONE;
867 : }
868 :
869 : #ifdef SIGBUS
870 : static PyObject *
871 0 : faulthandler_sigbus(PyObject *self, PyObject *args)
872 : {
873 0 : raise(SIGBUS);
874 0 : Py_RETURN_NONE;
875 : }
876 : #endif
877 :
878 : #ifdef SIGILL
879 : static PyObject *
880 0 : faulthandler_sigill(PyObject *self, PyObject *args)
881 : {
882 0 : raise(SIGILL);
883 0 : Py_RETURN_NONE;
884 : }
885 : #endif
886 :
887 : static PyObject *
888 0 : faulthandler_fatal_error_py(PyObject *self, PyObject *args)
889 : {
890 : char *message;
891 0 : if (!PyArg_ParseTuple(args, "y:fatal_error", &message))
892 0 : return NULL;
893 0 : Py_FatalError(message);
894 0 : Py_RETURN_NONE;
895 : }
896 :
897 : #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
898 : static void*
899 0 : stack_overflow(void *min_sp, void *max_sp, size_t *depth)
900 : {
901 : /* allocate 4096 bytes on the stack at each call */
902 : unsigned char buffer[4096];
903 0 : void *sp = &buffer;
904 0 : *depth += 1;
905 0 : if (sp < min_sp || max_sp < sp)
906 0 : return sp;
907 0 : buffer[0] = 1;
908 0 : buffer[4095] = 0;
909 0 : return stack_overflow(min_sp, max_sp, depth);
910 : }
911 :
912 : static PyObject *
913 0 : faulthandler_stack_overflow(PyObject *self)
914 : {
915 : size_t depth, size;
916 0 : char *sp = (char *)&depth, *stop;
917 :
918 0 : depth = 0;
919 0 : stop = stack_overflow(sp - STACK_OVERFLOW_MAX_SIZE,
920 : sp + STACK_OVERFLOW_MAX_SIZE,
921 : &depth);
922 0 : if (sp < stop)
923 0 : size = stop - sp;
924 : else
925 0 : size = sp - stop;
926 0 : PyErr_Format(PyExc_RuntimeError,
927 : "unable to raise a stack overflow (allocated %zu bytes "
928 : "on the stack, %zu recursive calls)",
929 : size, depth);
930 0 : return NULL;
931 : }
932 : #endif
933 :
934 :
935 : static int
936 0 : faulthandler_traverse(PyObject *module, visitproc visit, void *arg)
937 : {
938 : #ifdef FAULTHANDLER_USER
939 : unsigned int signum;
940 : #endif
941 :
942 : #ifdef FAULTHANDLER_LATER
943 0 : Py_VISIT(thread.file);
944 : #endif
945 : #ifdef FAULTHANDLER_USER
946 0 : if (user_signals != NULL) {
947 0 : for (signum=0; signum < NSIG; signum++)
948 0 : Py_VISIT(user_signals[signum].file);
949 : }
950 : #endif
951 0 : Py_VISIT(fatal_error.file);
952 0 : return 0;
953 : }
954 :
955 : PyDoc_STRVAR(module_doc,
956 : "faulthandler module.");
957 :
958 : static PyMethodDef module_methods[] = {
959 : {"enable",
960 : (PyCFunction)faulthandler_enable, METH_VARARGS|METH_KEYWORDS,
961 : PyDoc_STR("enable(file=sys.stderr, all_threads=True): "
962 : "enable the fault handler")},
963 : {"disable", (PyCFunction)faulthandler_disable_py, METH_NOARGS,
964 : PyDoc_STR("disable(): disable the fault handler")},
965 : {"is_enabled", (PyCFunction)faulthandler_is_enabled, METH_NOARGS,
966 : PyDoc_STR("is_enabled()->bool: check if the handler is enabled")},
967 : {"dump_traceback",
968 : (PyCFunction)faulthandler_dump_traceback_py, METH_VARARGS|METH_KEYWORDS,
969 : PyDoc_STR("dump_traceback(file=sys.stderr, all_threads=True): "
970 : "dump the traceback of the current thread, or of all threads "
971 : "if all_threads is True, into file")},
972 : #ifdef FAULTHANDLER_LATER
973 : {"dump_traceback_later",
974 : (PyCFunction)faulthandler_dump_traceback_later, METH_VARARGS|METH_KEYWORDS,
975 : PyDoc_STR("dump_traceback_later(timeout, repeat=False, file=sys.stderrn, exit=False):\n"
976 : "dump the traceback of all threads in timeout seconds,\n"
977 : "or each timeout seconds if repeat is True. If exit is True, "
978 : "call _exit(1) which is not safe.")},
979 : {"cancel_dump_traceback_later",
980 : (PyCFunction)faulthandler_cancel_dump_traceback_later_py, METH_NOARGS,
981 : PyDoc_STR("cancel_dump_traceback_later():\ncancel the previous call "
982 : "to dump_traceback_later().")},
983 : #endif
984 :
985 : #ifdef FAULTHANDLER_USER
986 : {"register",
987 : (PyCFunction)faulthandler_register_py, METH_VARARGS|METH_KEYWORDS,
988 : PyDoc_STR("register(signum, file=sys.stderr, all_threads=True, chain=False): "
989 : "register an handler for the signal 'signum': dump the "
990 : "traceback of the current thread, or of all threads if "
991 : "all_threads is True, into file")},
992 : {"unregister",
993 : faulthandler_unregister_py, METH_VARARGS|METH_KEYWORDS,
994 : PyDoc_STR("unregister(signum): unregister the handler of the signal "
995 : "'signum' registered by register()")},
996 : #endif
997 :
998 : {"_read_null", faulthandler_read_null, METH_VARARGS,
999 : PyDoc_STR("_read_null(release_gil=False): read from NULL, raise "
1000 : "a SIGSEGV or SIGBUS signal depending on the platform")},
1001 : {"_sigsegv", faulthandler_sigsegv, METH_VARARGS,
1002 : PyDoc_STR("_sigsegv(): raise a SIGSEGV signal")},
1003 : {"_sigabrt", faulthandler_sigabrt, METH_VARARGS,
1004 : PyDoc_STR("_sigabrt(): raise a SIGABRT signal")},
1005 : {"_sigfpe", (PyCFunction)faulthandler_sigfpe, METH_NOARGS,
1006 : PyDoc_STR("_sigfpe(): raise a SIGFPE signal")},
1007 : #ifdef SIGBUS
1008 : {"_sigbus", (PyCFunction)faulthandler_sigbus, METH_NOARGS,
1009 : PyDoc_STR("_sigbus(): raise a SIGBUS signal")},
1010 : #endif
1011 : #ifdef SIGILL
1012 : {"_sigill", (PyCFunction)faulthandler_sigill, METH_NOARGS,
1013 : PyDoc_STR("_sigill(): raise a SIGILL signal")},
1014 : #endif
1015 : {"_fatal_error", faulthandler_fatal_error_py, METH_VARARGS,
1016 : PyDoc_STR("_fatal_error(message): call Py_FatalError(message)")},
1017 : #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1018 : {"_stack_overflow", (PyCFunction)faulthandler_stack_overflow, METH_NOARGS,
1019 : PyDoc_STR("_stack_overflow(): recursive call to raise a stack overflow")},
1020 : #endif
1021 : {NULL, NULL} /* sentinel */
1022 : };
1023 :
1024 : static struct PyModuleDef module_def = {
1025 : PyModuleDef_HEAD_INIT,
1026 : "faulthandler",
1027 : module_doc,
1028 : 0, /* non-negative size to be able to unload the module */
1029 : module_methods,
1030 : NULL,
1031 : faulthandler_traverse,
1032 : NULL,
1033 : NULL
1034 : };
1035 :
1036 : PyMODINIT_FUNC
1037 0 : PyInit_faulthandler(void)
1038 : {
1039 0 : return PyModule_Create(&module_def);
1040 : }
1041 :
1042 : /* Call faulthandler.enable() if the PYTHONFAULTHANDLER environment variable
1043 : is defined, or if sys._xoptions has a 'faulthandler' key. */
1044 :
1045 : static int
1046 1 : faulthandler_env_options(void)
1047 : {
1048 : PyObject *xoptions, *key, *module, *res;
1049 : _Py_IDENTIFIER(enable);
1050 :
1051 1 : if (!Py_GETENV("PYTHONFAULTHANDLER")) {
1052 : int has_key;
1053 :
1054 1 : xoptions = PySys_GetXOptions();
1055 1 : if (xoptions == NULL)
1056 0 : return -1;
1057 :
1058 1 : key = PyUnicode_FromString("faulthandler");
1059 1 : if (key == NULL)
1060 0 : return -1;
1061 :
1062 1 : has_key = PyDict_Contains(xoptions, key);
1063 1 : Py_DECREF(key);
1064 1 : if (!has_key)
1065 1 : return 0;
1066 : }
1067 :
1068 0 : module = PyImport_ImportModule("faulthandler");
1069 0 : if (module == NULL) {
1070 0 : return -1;
1071 : }
1072 0 : res = _PyObject_CallMethodId(module, &PyId_enable, "");
1073 0 : Py_DECREF(module);
1074 0 : if (res == NULL)
1075 0 : return -1;
1076 0 : Py_DECREF(res);
1077 0 : return 0;
1078 : }
1079 :
1080 1 : int _PyFaulthandler_Init(void)
1081 : {
1082 : #ifdef HAVE_SIGALTSTACK
1083 : int err;
1084 :
1085 : /* Try to allocate an alternate stack for faulthandler() signal handler to
1086 : * be able to allocate memory on the stack, even on a stack overflow. If it
1087 : * fails, ignore the error. */
1088 1 : stack.ss_flags = 0;
1089 1 : stack.ss_size = SIGSTKSZ;
1090 1 : stack.ss_sp = PyMem_Malloc(stack.ss_size);
1091 1 : if (stack.ss_sp != NULL) {
1092 1 : err = sigaltstack(&stack, NULL);
1093 1 : if (err) {
1094 0 : PyMem_Free(stack.ss_sp);
1095 0 : stack.ss_sp = NULL;
1096 : }
1097 : }
1098 : #endif
1099 : #ifdef FAULTHANDLER_LATER
1100 1 : thread.file = NULL;
1101 1 : thread.cancel_event = PyThread_allocate_lock();
1102 1 : thread.running = PyThread_allocate_lock();
1103 1 : if (!thread.cancel_event || !thread.running) {
1104 0 : PyErr_SetString(PyExc_RuntimeError,
1105 : "could not allocate locks for faulthandler");
1106 0 : return -1;
1107 : }
1108 1 : PyThread_acquire_lock(thread.cancel_event, 1);
1109 : #endif
1110 :
1111 1 : return faulthandler_env_options();
1112 : }
1113 :
1114 0 : void _PyFaulthandler_Fini(void)
1115 : {
1116 : #ifdef FAULTHANDLER_USER
1117 : unsigned int signum;
1118 : #endif
1119 :
1120 : #ifdef FAULTHANDLER_LATER
1121 : /* later */
1122 0 : if (thread.cancel_event) {
1123 0 : cancel_dump_traceback_later();
1124 0 : PyThread_release_lock(thread.cancel_event);
1125 0 : PyThread_free_lock(thread.cancel_event);
1126 0 : thread.cancel_event = NULL;
1127 : }
1128 0 : if (thread.running) {
1129 0 : PyThread_free_lock(thread.running);
1130 0 : thread.running = NULL;
1131 : }
1132 : #endif
1133 :
1134 : #ifdef FAULTHANDLER_USER
1135 : /* user */
1136 0 : if (user_signals != NULL) {
1137 0 : for (signum=0; signum < NSIG; signum++)
1138 0 : faulthandler_unregister(&user_signals[signum], signum);
1139 0 : free(user_signals);
1140 0 : user_signals = NULL;
1141 : }
1142 : #endif
1143 :
1144 : /* fatal */
1145 0 : faulthandler_disable();
1146 : #ifdef HAVE_SIGALTSTACK
1147 0 : if (stack.ss_sp != NULL) {
1148 0 : PyMem_Free(stack.ss_sp);
1149 0 : stack.ss_sp = NULL;
1150 : }
1151 : #endif
1152 0 : }
|