static void faulthandler_dump_traceback(int fd, int all_threads, PyInterpreterState *interp) { static volatile int reentrant = 0; PyThreadState *tstate; if (reentrant) return; reentrant = 1; #ifdef WITH_THREAD /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and are thus delivered to the thread that caused the fault. Get the Python thread state of the current thread. PyThreadState_Get() doesn't give the state of the thread that caused the fault if the thread released the GIL, and so this function cannot be used. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); #else tstate = PyThreadState_Get(); #endif if (all_threads) _Py_DumpTracebackThreads(fd, interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(fd, tstate); } reentrant = 0; }
static void faulthandler_alarm(int signum) { PyThreadState *tstate; const char* errmsg; int ok; _Py_write_noraise(fault_alarm.fd, fault_alarm.header, fault_alarm.header_len); /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); errmsg = _Py_DumpTracebackThreads(fault_alarm.fd, fault_alarm.interp, tstate); ok = (errmsg == NULL); if (ok && fault_alarm.repeat) alarm(fault_alarm.timeout); else /* don't call Py_CLEAR() here because it may call _Py_Dealloc() which is not signal safe */ alarm(0); if (fault_alarm.exit) _exit(1); }
static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_ms, 0); if (st == PY_LOCK_ACQUIRED) { /* Cancelled by user */ break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.cancel_event); PyThread_release_lock(thread.join_event); }
static void _Py_FatalError_DumpTracebacks(int fd) { fputc('\n', stderr); fflush(stderr); /* display the current Python stack */ _Py_DumpTracebackThreads(fd, NULL, NULL); }
static void faulthandler_user(int signum) { user_signal_t *user; PyThreadState *tstate; int save_errno = errno; user = &user_signals[signum]; if (!user->enabled) return; #ifdef WITH_THREAD /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); #else tstate = PyThreadState_Get(); #endif if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(user->fd, tstate); } #ifdef HAVE_SIGACTION if (user->chain) { (void)sigaction(signum, &user->previous, NULL); errno = save_errno; /* call the previous signal handler */ raise(signum); save_errno = errno; (void)faulthandler_register(signum, user->chain, NULL); errno = save_errno; } #else if (user->chain) { errno = save_errno; /* call the previous signal handler */ user->previous(signum); } #endif }
void Py_FatalError(const char *msg) { const int fd = fileno(stderr); PyThreadState *tstate; fprintf(stderr, "Fatal Python error: %s\n", msg); fflush(stderr); /* it helps in Windows debug build */ if (PyErr_Occurred()) { PyErr_PrintEx(0); } else { tstate = _Py_atomic_load_relaxed(&_PyThreadState_Current); if (tstate != NULL) { fputc('\n', stderr); fflush(stderr); _Py_DumpTracebackThreads(fd, tstate->interp, tstate); } _PyFaulthandler_Fini(); } #ifdef MS_WINDOWS { size_t len = strlen(msg); WCHAR* buffer; size_t i; /* Convert the message to wchar_t. This uses a simple one-to-one conversion, assuming that the this error message actually uses ASCII only. If this ceases to be true, we will have to convert. */ buffer = alloca( (len+1) * (sizeof *buffer)); for( i=0; i<=len; ++i) buffer[i] = msg[i]; OutputDebugStringW(L"Fatal Python error: "); OutputDebugStringW(buffer); OutputDebugStringW(L"\n"); } #ifdef _DEBUG DebugBreak(); #endif #endif /* MS_WINDOWS */ abort(); }
static void faulthandler_thread(void *unused) { PyLockStatus st; const char* errmsg; PyThreadState *current; int ok; #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) sigset_t set; /* we don't want to receive any signal */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif do { st = PyThread_acquire_lock_timed(thread.cancel_event, thread.timeout_us, 0); if (st == PY_LOCK_ACQUIRED) { PyThread_release_lock(thread.cancel_event); break; } /* Timeout => dump traceback */ assert(st == PY_LOCK_FAILURE); /* get the thread holding the GIL, NULL if no thread hold the GIL */ current = _Py_atomic_load_relaxed(&_PyThreadState_Current); write(thread.fd, thread.header, thread.header_len); errmsg = _Py_DumpTracebackThreads(thread.fd, thread.interp, current); ok = (errmsg == NULL); if (thread.exit) _exit(1); } while (ok && thread.repeat); /* The only way out */ PyThread_release_lock(thread.running); }
static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 1; PyThreadState *tstate; const char *errmsg; int fd; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:dump_traceback", kwlist, &file, &all_threads)) return NULL; fd = faulthandler_get_fileno(&file); if (fd < 0) return NULL; tstate = get_thread_state(); if (tstate == NULL) return NULL; if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate); if (errmsg != NULL) { PyErr_SetString(PyExc_RuntimeError, errmsg); return NULL; } } else { _Py_DumpTraceback(fd, tstate); } if (PyErr_CheckSignals()) return NULL; Py_RETURN_NONE; }
static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 0; PyThreadState *tstate; const char *errmsg; int fd; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:dump_traceback", kwlist, &file, &all_threads)) return NULL; file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; /* The caller holds the GIL and so PyThreadState_Get() can be used */ tstate = PyThreadState_Get(); if (tstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "unable to get the current thread state"); return NULL; } if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, tstate->interp, tstate); if (errmsg != NULL) { PyErr_SetString(PyExc_RuntimeError, errmsg); return NULL; } } else { _Py_DumpTraceback(fd, tstate); } Py_RETURN_NONE; }
static void faulthandler_user(int signum) { user_signal_t *user; PyThreadState *tstate; user = &user_signals[signum]; if (!user->enabled) return; /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); else { if (tstate == NULL) return; _Py_DumpTraceback(user->fd, tstate); } }
static void faulthandler_fatal_error(int signum) { const int fd = fatal_error.fd; unsigned int i; fault_handler_t *handler = NULL; PyThreadState *tstate; int save_errno = errno; if (!fatal_error.enabled) return; for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; if (handler->signum == signum) break; } if (handler == NULL) { /* faulthandler_nsignals == 0 (unlikely) */ return; } /* restore the previous handler */ #ifdef HAVE_SIGACTION (void)sigaction(signum, &handler->previous, NULL); #else (void)signal(signum, handler->previous); #endif handler->enabled = 0; PUTS(fd, "Fatal Python error: "); PUTS(fd, handler->name); PUTS(fd, "\n\n"); #ifdef WITH_THREAD /* SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and are thus delivered to the thread that caused the fault. Get the Python thread state of the current thread. PyThreadState_Get() doesn't give the state of the thread that caused the fault if the thread released the GIL, and so this function cannot be used. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); #else tstate = PyThreadState_Get(); #endif if (fatal_error.all_threads) _Py_DumpTracebackThreads(fd, fatal_error.interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(fd, tstate); } errno = save_errno; #ifdef MS_WINDOWS if (signum == SIGSEGV) { /* don't explicitly call the previous handler for SIGSEGV in this signal handler, because the Windows signal handler would not be called */ return; } #endif /* call the previous signal handler: it is called immediatly if we use sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */ raise(signum); }
static void _Py_PrintFatalError(int fd) { PyObject *ferr, *res; PyObject *exception, *v, *tb; int has_tb; PyThreadState *tstate; PyErr_Fetch(&exception, &v, &tb); if (exception == NULL) { /* No current exception */ goto display_stack; } ferr = _PySys_GetObjectId(&PyId_stderr); if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ goto display_stack; } PyErr_NormalizeException(&exception, &v, &tb); if (tb == NULL) { tb = Py_None; Py_INCREF(tb); } PyException_SetTraceback(v, tb); if (exception == NULL) { /* PyErr_NormalizeException() failed */ goto display_stack; } has_tb = (tb != Py_None); PyErr_Display(exception, v, tb); Py_XDECREF(exception); Py_XDECREF(v); Py_XDECREF(tb); /* sys.stderr may be buffered: call sys.stderr.flush() */ res = _PyObject_CallMethodId(ferr, &PyId_flush, ""); if (res == NULL) PyErr_Clear(); else Py_DECREF(res); if (has_tb) return; display_stack: #ifdef WITH_THREAD /* PyGILState_GetThisThreadState() works even if the GIL was released */ tstate = PyGILState_GetThisThreadState(); #else tstate = PyThreadState_GET(); #endif if (tstate == NULL) { /* _Py_DumpTracebackThreads() requires the thread state to display * frames */ return; } fputc('\n', stderr); fflush(stderr); /* display the current Python stack */ _Py_DumpTracebackThreads(fd, tstate->interp, tstate); }