diff options
| author | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 11:24:06 +0100 | 
|---|---|---|
| committer | Victor Stinner <victor.stinner@gmail.com> | 2015-03-24 11:24:06 +0100 | 
| commit | 0e98a76b65161b74a23f64e05a8075b46d908d10 (patch) | |
| tree | 0a997ce4fe390468530efbbc88c8d9dafd21346c /Python | |
| parent | 2e3998fae0996bbb349a4696071f0582f8c799c0 (diff) | |
| download | cpython-git-0e98a76b65161b74a23f64e05a8075b46d908d10.tar.gz | |
Issue #23571: Enhance Py_FatalError()
* Display the current Python stack if an exception was raised but the exception
  has no traceback
* Disable faulthandler if an exception was raised (before it was only disabled
  if no exception was raised)
* To display the current Python stack, call PyGILState_GetThisThreadState()
  which works even if the GIL was released
Diffstat (limited to 'Python')
| -rw-r--r-- | Python/pythonrun.c | 73 | 
1 files changed, 60 insertions, 13 deletions
| diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 0327830247..3217a9cbd0 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2587,28 +2587,75 @@ cleanup:      }  } +/* 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. */ + +static void +_Py_PrintFatalError(int fd) +{ +    PyObject *exception, *v, *tb; +    int has_tb; +    PyThreadState *tstate; + +    PyErr_Fetch(&exception, &v, &tb); +    if (exception == NULL) { +        /* No current 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) { +        /* too bad, PyErr_NormalizeException() failed */ +        goto display_stack; +    } + +    has_tb = (tb != NULL && tb != Py_None); +    PyErr_Display(exception, v, tb); +    Py_XDECREF(exception); +    Py_XDECREF(v); +    Py_XDECREF(tb); +    if (has_tb) +        return; + +display_stack: +    /* PyGILState_GetThisThreadState() works even if the GIL was released */ +    tstate = PyGILState_GetThisThreadState(); +    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 fatal error message and abort */  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(); -    } + +    _Py_PrintFatalError(fd); + +    /* The main purpose of faulthandler is to display the traceback. We already +     * did our best to display it. So faulthandler can now be disabled. */ +    _PyFaulthandler_Fini();  #ifdef MS_WINDOWS      { | 
