mirror of
https://github.com/python/cpython.git
synced 2025-08-29 05:05:03 +00:00
bpo-30697: Fix PyErr_NormalizeException() when no memory (GH-2327)
This commit is contained in:
parent
275d2d9c46
commit
56d1f5ca32
8 changed files with 203 additions and 53 deletions
|
@ -218,20 +218,24 @@ PyErr_ExceptionMatches(PyObject *exc)
|
|||
}
|
||||
|
||||
|
||||
#ifndef Py_NORMALIZE_RECURSION_LIMIT
|
||||
#define Py_NORMALIZE_RECURSION_LIMIT 32
|
||||
#endif
|
||||
|
||||
/* Used in many places to normalize a raised exception, including in
|
||||
eval_code2(), do_raise(), and PyErr_Print()
|
||||
|
||||
XXX: should PyErr_NormalizeException() also call
|
||||
PyException_SetTraceback() with the resulting value and tb?
|
||||
*/
|
||||
void
|
||||
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
||||
static void
|
||||
PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
|
||||
PyObject **tb, int recursion_depth)
|
||||
{
|
||||
PyObject *type = *exc;
|
||||
PyObject *value = *val;
|
||||
PyObject *inclass = NULL;
|
||||
PyObject *initial_tb = NULL;
|
||||
PyThreadState *tstate = NULL;
|
||||
|
||||
if (type == NULL) {
|
||||
/* There was no exception, so nothing to do. */
|
||||
|
@ -293,6 +297,10 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
|||
finally:
|
||||
Py_DECREF(type);
|
||||
Py_DECREF(value);
|
||||
if (recursion_depth + 1 == Py_NORMALIZE_RECURSION_LIMIT) {
|
||||
PyErr_SetString(PyExc_RecursionError, "maximum recursion depth "
|
||||
"exceeded while normalizing an exception");
|
||||
}
|
||||
/* If the new exception doesn't set a traceback and the old
|
||||
exception had a traceback, use the old traceback for the
|
||||
new exception. It's better than nothing.
|
||||
|
@ -305,20 +313,26 @@ finally:
|
|||
else
|
||||
Py_DECREF(initial_tb);
|
||||
}
|
||||
/* normalize recursively */
|
||||
tstate = PyThreadState_GET();
|
||||
if (++tstate->recursion_depth > Py_GetRecursionLimit()) {
|
||||
--tstate->recursion_depth;
|
||||
/* throw away the old exception and use the recursion error instead */
|
||||
Py_INCREF(PyExc_RecursionError);
|
||||
Py_SETREF(*exc, PyExc_RecursionError);
|
||||
Py_INCREF(PyExc_RecursionErrorInst);
|
||||
Py_SETREF(*val, PyExc_RecursionErrorInst);
|
||||
/* just keeping the old traceback */
|
||||
return;
|
||||
/* 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) {
|
||||
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
|
||||
Py_FatalError("Cannot recover from MemoryErrors "
|
||||
"while normalizing exceptions.");
|
||||
}
|
||||
else {
|
||||
Py_FatalError("Cannot recover from the recursive normalization "
|
||||
"of an exception.");
|
||||
}
|
||||
}
|
||||
PyErr_NormalizeException(exc, val, tb);
|
||||
--tstate->recursion_depth;
|
||||
PyErr_NormalizeExceptionEx(exc, val, tb, recursion_depth);
|
||||
}
|
||||
|
||||
void
|
||||
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
|
||||
{
|
||||
PyErr_NormalizeExceptionEx(exc, val, tb, 0);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue