summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorxdegaye <xdegaye@gmail.com>2017-10-26 15:48:48 (GMT)
committerGitHub <noreply@github.com>2017-10-26 15:48:48 (GMT)
commit4b27d51222be751125e6800453a39360a2dec11d (patch)
treec41987cae0bf6f909eb7fb0b454a8746912b2403 /Python
parentd94ef8fe94ed192a24a71117c07e6c7b60a8ac6c (diff)
downloadcpython-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.c46
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);
}