bpo-28994: PyErr_NormalizeException() no longer use C stack for recursion. (#2035)
MemoryError raised when normalizing a RecursionError raised during exception normalization now not always causes a fatal error.
This commit is contained in:
parent
1b46131ae4
commit
cf296537f1
|
@ -228,20 +228,20 @@ PyErr_ExceptionMatches(PyObject *exc)
|
||||||
XXX: should PyErr_NormalizeException() also call
|
XXX: should PyErr_NormalizeException() also call
|
||||||
PyException_SetTraceback() with the resulting value and tb?
|
PyException_SetTraceback() with the resulting value and tb?
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
|
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
||||||
PyObject **tb, int recursion_depth)
|
|
||||||
{
|
{
|
||||||
PyObject *type = *exc;
|
int recursion_depth = 0;
|
||||||
PyObject *value = *val;
|
PyObject *type, *value, *initial_tb;
|
||||||
PyObject *inclass = NULL;
|
|
||||||
PyObject *initial_tb = NULL;
|
|
||||||
|
|
||||||
|
restart:
|
||||||
|
type = *exc;
|
||||||
if (type == NULL) {
|
if (type == NULL) {
|
||||||
/* There was no exception, so nothing to do. */
|
/* There was no exception, so nothing to do. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = *val;
|
||||||
/* If PyErr_SetNone() was used, the value will have been actually
|
/* If PyErr_SetNone() was used, the value will have been actually
|
||||||
set to NULL.
|
set to NULL.
|
||||||
*/
|
*/
|
||||||
|
@ -250,54 +250,52 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
|
||||||
Py_INCREF(value);
|
Py_INCREF(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyExceptionInstance_Check(value))
|
|
||||||
inclass = PyExceptionInstance_Class(value);
|
|
||||||
|
|
||||||
/* Normalize the exception so that if the type is a class, the
|
/* Normalize the exception so that if the type is a class, the
|
||||||
value will be an instance.
|
value will be an instance.
|
||||||
*/
|
*/
|
||||||
if (PyExceptionClass_Check(type)) {
|
if (PyExceptionClass_Check(type)) {
|
||||||
int is_subclass;
|
PyObject *inclass = NULL;
|
||||||
if (inclass) {
|
int is_subclass = 0;
|
||||||
is_subclass = PyObject_IsSubclass(inclass, type);
|
|
||||||
if (is_subclass < 0)
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
is_subclass = 0;
|
|
||||||
|
|
||||||
/* if the value was not an instance, or is not an instance
|
if (PyExceptionInstance_Check(value)) {
|
||||||
|
inclass = PyExceptionInstance_Class(value);
|
||||||
|
is_subclass = PyObject_IsSubclass(inclass, type);
|
||||||
|
if (is_subclass < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the value was not an instance, or is not an instance
|
||||||
whose class is (or is derived from) type, then use the
|
whose class is (or is derived from) type, then use the
|
||||||
value as an argument to instantiation of the type
|
value as an argument to instantiation of the type
|
||||||
class.
|
class.
|
||||||
*/
|
*/
|
||||||
if (!inclass || !is_subclass) {
|
if (!is_subclass) {
|
||||||
PyObject *fixed_value;
|
PyObject *fixed_value = _PyErr_CreateException(type, value);
|
||||||
|
|
||||||
fixed_value = _PyErr_CreateException(type, value);
|
|
||||||
if (fixed_value == NULL) {
|
if (fixed_value == NULL) {
|
||||||
goto finally;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
value = fixed_value;
|
value = fixed_value;
|
||||||
}
|
}
|
||||||
/* if the class of the instance doesn't exactly match the
|
/* If the class of the instance doesn't exactly match the
|
||||||
class of the type, believe the instance
|
class of the type, believe the instance.
|
||||||
*/
|
*/
|
||||||
else if (inclass != type) {
|
else if (inclass != type) {
|
||||||
|
Py_INCREF(inclass);
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
type = inclass;
|
type = inclass;
|
||||||
Py_INCREF(type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*exc = type;
|
*exc = type;
|
||||||
*val = value;
|
*val = value;
|
||||||
return;
|
return;
|
||||||
finally:
|
|
||||||
|
error:
|
||||||
Py_DECREF(type);
|
Py_DECREF(type);
|
||||||
Py_DECREF(value);
|
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 "
|
PyErr_SetString(PyExc_RecursionError, "maximum recursion depth "
|
||||||
"exceeded while normalizing an exception");
|
"exceeded while normalizing an exception");
|
||||||
}
|
}
|
||||||
|
@ -307,16 +305,18 @@ finally:
|
||||||
*/
|
*/
|
||||||
initial_tb = *tb;
|
initial_tb = *tb;
|
||||||
PyErr_Fetch(exc, val, tb);
|
PyErr_Fetch(exc, val, tb);
|
||||||
|
assert(*exc != NULL);
|
||||||
if (initial_tb != NULL) {
|
if (initial_tb != NULL) {
|
||||||
if (*tb == NULL)
|
if (*tb == NULL)
|
||||||
*tb = initial_tb;
|
*tb = initial_tb;
|
||||||
else
|
else
|
||||||
Py_DECREF(initial_tb);
|
Py_DECREF(initial_tb);
|
||||||
}
|
}
|
||||||
/* Normalize recursively.
|
/* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded, and the
|
||||||
* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded and the
|
corresponding RecursionError could not be normalized, and the
|
||||||
* corresponding RecursionError could not be normalized.*/
|
MemoryError raised when normalize this RecursionError could not be
|
||||||
if (++recursion_depth > Py_NORMALIZE_RECURSION_LIMIT) {
|
normalized. */
|
||||||
|
if (recursion_depth >= Py_NORMALIZE_RECURSION_LIMIT + 2) {
|
||||||
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
|
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
|
||||||
Py_FatalError("Cannot recover from MemoryErrors "
|
Py_FatalError("Cannot recover from MemoryErrors "
|
||||||
"while normalizing exceptions.");
|
"while normalizing exceptions.");
|
||||||
|
@ -326,13 +326,7 @@ finally:
|
||||||
"of an exception.");
|
"of an exception.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyErr_NormalizeExceptionEx(exc, val, tb, recursion_depth);
|
goto restart;
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
|
||||||
{
|
|
||||||
PyErr_NormalizeExceptionEx(exc, val, tb, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue