diff options
author | xdegaye <xdegaye@gmail.com> | 2017-10-26 13:09:06 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-26 13:09:06 (GMT) |
commit | 56d1f5ca32892c7643eb8cee49c40c1644f1abfe (patch) | |
tree | 696b62e9bdd22063a894ecb5a7b9eafe60385edf /Python/errors.c | |
parent | 275d2d9c4663a1ea8d1f7c8778567a735b0372c1 (diff) | |
download | cpython-56d1f5ca32892c7643eb8cee49c40c1644f1abfe.zip cpython-56d1f5ca32892c7643eb8cee49c40c1644f1abfe.tar.gz cpython-56d1f5ca32892c7643eb8cee49c40c1644f1abfe.tar.bz2 |
bpo-30697: Fix PyErr_NormalizeException() when no memory (GH-2327)
Diffstat (limited to 'Python/errors.c')
-rw-r--r-- | Python/errors.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/Python/errors.c b/Python/errors.c index 51fc791..13ebb19 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -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); } |