diff options
author | xdegaye <xdegaye@gmail.com> | 2017-10-26 15:48:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-26 15:48:48 (GMT) |
commit | 4b27d51222be751125e6800453a39360a2dec11d (patch) | |
tree | c41987cae0bf6f909eb7fb0b454a8746912b2403 /Python | |
parent | d94ef8fe94ed192a24a71117c07e6c7b60a8ac6c (diff) | |
download | cpython-4b27d51222be751125e6800453a39360a2dec11d.zip cpython-4b27d51222be751125e6800453a39360a2dec11d.tar.gz cpython-4b27d51222be751125e6800453a39360a2dec11d.tar.bz2 |
[3.6] bpo-30697: Fix PyErr_NormalizeException() when no memory (GH-2327). (#4135)
(cherry picked from commit 56d1f5ca32892c7643eb8cee49c40c1644f1abfe)
Diffstat (limited to 'Python')
-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 2f39f9d..78c0524 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -217,20 +217,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. */ @@ -292,6 +296,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. @@ -304,20 +312,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); } |