summaryrefslogtreecommitdiffstats
path: root/Python/errors.c
diff options
context:
space:
mode:
authorxdegaye <xdegaye@gmail.com>2017-10-26 13:09:06 (GMT)
committerGitHub <noreply@github.com>2017-10-26 13:09:06 (GMT)
commit56d1f5ca32892c7643eb8cee49c40c1644f1abfe (patch)
tree696b62e9bdd22063a894ecb5a7b9eafe60385edf /Python/errors.c
parent275d2d9c4663a1ea8d1f7c8778567a735b0372c1 (diff)
downloadcpython-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.c46
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);
}