8000 bpo-28994: PyErr_NormalizeException() no longer recursive. by serhiy-storchaka · Pull Request #2035 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-28994: PyErr_NormalizeException() no longer recursive. #2035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 33 additions & 39 deletions Python/errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,20 +228,20 @@ PyErr_ExceptionMatches(PyObject *exc)
XXX: should PyErr_NormalizeException() also call
PyException_SetTraceback() with the resulting value and tb?
*/
static void
PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
PyObject **tb, int recursion_depth)
void
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
{
PyObject *type = *exc;
PyObject *value = *val;
PyObject *inclass = NULL;
PyObject *initial_tb = NULL;
int recursion_depth = 0;
PyObject *type, *value, *initial_tb;

restart:
type = *exc;
if (type == NULL) {
/* There was no exception, so nothing to do. */
return;
}

value = *val;
/* If PyErr_SetNone() was used, the value will have been actually
set to NULL.
*/
Expand All @@ -250,54 +250,52 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
Py_INCREF(value);
}

if (PyExceptionInstance_Check(value))
inclass = PyExceptionInstance_Class(value);

/* Normalize the exception so that if the type is a class, the
value will be an instance.
*/
if (PyExceptionClass_Check(type)) {
int is_subclass;
if (inclass) {
PyObject *inclass = NULL;
int is_subclass = 0;

if (PyExceptionInstance_Check(value)) {
inclass = PyExceptionInstance_Class(value);
is_subclass = PyObject_IsSubclass(inclass, type);
if (is_subclass < 0)
goto finally;
if (is_subclass < 0) {
goto error;
}
}
else
is_subclass = 0;

/* if the value was not an instance, or is not an instance
/* If the value was not an instance, or is not an instance
whose class is (or is derived from) type, then use the
value as an argument to instantiation of the type
class.
*/
if (!inclass || !is_subclass) {
PyObject *fixed_value;

fixed_value = _PyErr_CreateException(type, value);
if (!is_subclass) {
PyObject *fixed_value = _PyErr_CreateException(type, value);
if (fixed_value == NULL) {
goto finally;
goto error;
}

Py_DECREF(value);
value = fixed_value;
}
/* if the class of the instance doesn't exactly match the
class of the type, believe the instance
/* If the class of the instance doesn't exactly match the
class of the type, believe the instance.
*/
else if (inclass != type) {
Py_INCREF(inclass);
Py_DECREF(type);
type = inclass;
Py_INCREF(type);
}
}
*exc = type;
*val = value;
return;
finally:

error:
Py_DECREF(type);
Py_DECREF(value);
if (recursion_depth + 1 == Py_NORMALIZE_RECURSION_LIMIT) {
recursion_depth++;
if (recursion_depth == Py_NORMALIZE_RECURSION_LIMIT) {
PyErr_SetString(PyExc_RecursionError, "maximum recursion depth "
"exceeded while normalizing an exception");
}
Expand All @@ -307,16 +305,18 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
*/
initial_tb = *tb;
PyErr_Fetch(exc, val, tb);
assert(*exc != NULL);
if (initial_tb != NULL) {
if (*tb == NULL)
*tb = initial_tb;
else
Py_DECREF(initial_tb);
}
/* Normalize recursively.
* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded and the
* corresponding RecursionError could not be normalized.*/
if (++recursion_depth > Py_NORMALIZE_RECURSION_LIMIT) {
/* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded, and the
corresponding RecursionError could not be normalized, and the
MemoryError raised when normalize this RecursionError could not be
normalized. */
if (recursion_depth >= Py_NORMALIZE_RECURSION_LIMIT + 2) {
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
Py_FatalError("Cannot recover from MemoryErrors "
"while normalizing exceptions.");
Expand All @@ -326,13 +326,7 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
"of an exception.");
}
}
PyErr_NormalizeExceptionEx(exc, val, tb, recursion_depth);
}

void
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
{
PyErr_NormalizeExceptionEx(exc, val, tb, 0);
goto restart;
}


Expand Down
0