diff options
| -rw-r--r-- | Python/pylifecycle.c | 84 | 
1 files changed, 50 insertions, 34 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4f5efc963c..c4a6d7c955 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1241,31 +1241,62 @@ initstdio(void)  } +static void +_Py_FatalError_DumpTracebacks(int fd) +{ +    PyThreadState *tstate; + +#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); +} +  /* Print the current exception (if an exception is set) with its traceback, - * or display the current Python stack. - * - * Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is - * called on catastrophic cases. */ +   or display the current Python stack. -static void -_Py_PrintFatalError(int fd) +   Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is +   called on catastrophic cases. + +   Return 1 if the traceback was displayed, 0 otherwise. */ + +static int +_Py_FatalError_PrintExc(int fd)  {      PyObject *ferr, *res;      PyObject *exception, *v, *tb;      int has_tb; -    PyThreadState *tstate; + +    if (PyThreadState_GET() == NULL) { +        /* The GIL is released: trying to acquire it is likely to deadlock, +           just give up. */ +        return 0; +    }      PyErr_Fetch(&exception, &v, &tb);      if (exception == NULL) {          /* No current exception */ -        goto display_stack; +        return 0;      }      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; +        return 0;      }      PyErr_NormalizeException(&exception, &v, &tb); @@ -1276,7 +1307,7 @@ _Py_PrintFatalError(int fd)      PyException_SetTraceback(v, tb);      if (exception == NULL) {          /* PyErr_NormalizeException() failed */ -        goto display_stack; +        return 0;      }      has_tb = (tb != Py_None); @@ -1292,28 +1323,9 @@ _Py_PrintFatalError(int fd)      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); +    return has_tb;  } +  /* Print fatal error message and abort */  void @@ -1339,10 +1351,14 @@ Py_FatalError(const char *msg)      /* Print the exception (if an exception is set) with its traceback,       * or display the current Python stack. */ -    _Py_PrintFatalError(fd); +    if (!_Py_FatalError_PrintExc(fd)) +        _Py_FatalError_DumpTracebacks(fd); -    /* Flush sys.stdout and sys.stderr */ -    flush_std_files(); +    /* Check if the current Python thread hold the GIL */ +    if (PyThreadState_GET() != NULL) { +        /* Flush sys.stdout and sys.stderr */ +        flush_std_files(); +    }      /* The main purpose of faulthandler is to display the traceback. We already       * did our best to display it. So faulthandler can now be disabled.  | 
