-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
bpo-30697: fix PyErr_NormalizeException() when no memory #2327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d190732
56ebb33
f824885
5fc42a2
fb05d40
e53b5a8
e1bd62b
af6896e
d81ef9c
312ec15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -217,6 +217,10 @@ 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() | ||
|
||
|
@@ -230,7 +234,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) | |
PyObject *value = *val; | ||
PyObject *inclass = NULL; | ||
PyObject *initial_tb = NULL; | ||
PyThreadState *tstate = NULL; | ||
static int recursion_depth = 0; | ||
|
||
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_Format(PyExc_RecursionError, "maximum recursion depth exceeded " | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A nit, but you can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or even There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The instantiation of the RecursionError object itself fails anyway upon its normalization when there is no memory (and a memory error is reported to the user and not the recursion error). So it seems there is no advantage in using PyErr_SetObject() with a pre-created static string object over PyErr_SetString() here. |
||
"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,21 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) | |
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; | ||
--recursion_depth; | ||
} | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it right to use a static variable instead of a threadstate-attached variable? What if the GIL is released somewhere in-between and the wrong thread gets the recursion error (or, worse, triggers a fatal error)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right of course. I will fix that.