bpo-36829: PyErr_WriteUnraisable() normalizes exception (GH-13507)

PyErr_WriteUnraisable() now creates a traceback object if there is no
current traceback. Moreover, call PyErr_NormalizeException() and
PyException_SetTraceback() to normalize the exception value. Ignore
silently any error.
This commit is contained in:
Victor Stinner 2019-05-23 01:00:58 +02:00 committed by GitHub
parent 5edcf26358
commit df22c03b93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 13 deletions

View file

@ -4,6 +4,7 @@
#include "Python.h"
#include "pycore_coreconfig.h"
#include "pycore_pystate.h"
#include "pycore_traceback.h"
#ifndef __STDC__
#ifndef MS_WINDOWS
@ -1048,7 +1049,7 @@ write_unraisable_exc_file(PyObject *exc_type, PyObject *exc_value,
}
}
if (!exc_type) {
if (exc_type == NULL || exc_type == Py_None) {
return -1;
}
@ -1106,6 +1107,7 @@ write_unraisable_exc_file(PyObject *exc_type, PyObject *exc_value,
}
}
}
if (PyFile_WriteString("\n", file) < 0) {
return -1;
}
@ -1177,6 +1179,24 @@ PyErr_WriteUnraisable(PyObject *obj)
goto default_hook;
}
if (exc_tb == NULL) {
struct _frame *frame = _PyThreadState_GET()->frame;
if (frame != NULL) {
exc_tb = _PyTraceBack_FromFrame(NULL, frame);
if (exc_tb == NULL) {
PyErr_Clear();
}
}
}
PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb);
if (exc_tb != NULL && exc_tb != Py_None && PyTraceBack_Check(exc_tb)) {
if (PyException_SetTraceback(exc_value, exc_tb) < 0) {
PyErr_Clear();
}
}
_Py_IDENTIFIER(unraisablehook);
PyObject *hook = _PySys_GetObjectId(&PyId_unraisablehook);
if (hook != NULL && hook != Py_None) {

View file

@ -227,13 +227,24 @@ PyTypeObject PyTraceBack_Type = {
tb_new, /* tp_new */
};
PyObject*
_PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
{
assert(tb_next == NULL || PyTraceBack_Check(tb_next));
assert(frame != NULL);
return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti,
PyFrame_GetLineNumber(frame));
}
int
PyTraceBack_Here(PyFrameObject *frame)
{
PyObject *exc, *val, *tb, *newtb;
PyErr_Fetch(&exc, &val, &tb);
newtb = tb_create_raw((PyTracebackObject *)tb, frame, frame->f_lasti,
PyFrame_GetLineNumber(frame));
newtb = _PyTraceBack_FromFrame(tb, frame);
if (newtb == NULL) {
_PyErr_ChainExceptions(exc, val, tb);
return -1;