8000 bpo-28994: PyErr_NormalizeException() no longer recursive. · python/cpython@4dcbd8f · GitHub
[go: up one dir, main page]

Skip to content

Commit 4dcbd8f

Browse files
bpo-28994: PyErr_NormalizeException() no longer recursive.
1 parent 09663de commit 4dcbd8f

File tree

1 file changed

+20
-14
lines changed

1 file changed

+20
-14
lines changed

Python/errors.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,18 @@ PyErr_ExceptionMatches(PyObject *exc)
226226
void
227227
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
228228
{
229-
PyObject *type = *exc;
230-
PyObject *value = *val;
231-
PyObject *inclass = NULL;
232-
PyObject *initial_tb = NULL;
233-
PyThreadState *tstate = NULL;
229+
int recursion_depth = 0;
230+
PyObject *type, *value, *initial_tb;
231+
PyThreadState *tstate;
234232

233+
restart:
234+
type = *exc;
235235
if (type == NULL) {
236236
/* There was no exception, so nothing to do. */
237237
return;
238238
}
239239

240+
value = *val;
240241
/* If PyErr_SetNone() was used, the value will have been actually
241242
set to NULL.
242243
*/
@@ -245,14 +246,18 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
245246
Py_INCREF(value);
246247
}
247248

248-
if (PyExceptionInstance_Check(value))
249-
inclass = PyExceptionInstance_Class(value);
250-
251249
/* Normalize the exception so that if the type is a class, the
252250
value will be an instance.
253251
*/
254252
if (PyExceptionClass_Check(type)) {
253+
PyObject *inclass;
255254
int is_subclass;
255+
256+
if (PyExceptionInstance_Check(value))
257+
inclass = PyExceptionInstance_Class(value);
258+
else
259+
inclass = NULL;
260+
256261
if (inclass) {
257262
is_subclass = PyObject_IsSubclass(inclass, type);
258263
if (is_subclass < 0)
@@ -266,7 +271,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
266271
value as an argument to instantiation of the type
267272
class.
268273
*/
269-
if (!inclass || !is_subclass) {
274+
if (!is_subclass) {
270275
PyObject *fixed_value;
271276

272277
fixed_value = _PyErr_CreateException(type, value);
@@ -289,6 +294,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
289294
*exc = type;
290295
*val = value;
291296
return;
297+
292298
finally:
293299
Py_DECREF(type);
294300
Py_DECREF(value);
@@ -298,6 +304,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
298304
*/
299305
initial_tb = *tb;
300306
PyErr_Fetch(exc, val, tb);
307+
assert(*exc != NULL);
301308
if (initial_tb != NULL) {
302309
if (*tb == NULL)
303310
*tb = initial_tb;
@@ -306,18 +313,17 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
306313
}
307314
/* normalize recursively */
308315
tstate = PyThreadState_GET();
309-
if (++tstate->recursion_depth > Py_GetRecursionLimit()) {
310-
--tstate->recursion_depth;
316+
if (++recursion_depth > Py_GetRecursionLimit() - tstate->recursion_depth) {
311317
/* throw away the old exception and use the recursion error instead */
312318
Py_INCREF(PyExc_RecursionError);
313319
Py_SETREF(*exc, PyExc_RecursionError);
314320
Py_INCREF(PyExc_RecursionErrorInst);
315-
Py_SETREF(*val, PyExc_RecursionErrorInst);
321+
Py_XSETREF(*val, PyExc_RecursionErrorInst);
316322
/* just keeping the old traceback */
317323
return;
318324
}
319-
PyErr_NormalizeException(exc, val, tb);
320-
--tstate->recursion_depth;
325+
/* eliminate tail recursion */
326+
goto restart;
321327
}
322328

323329

0 commit comments

Comments
 (0)
0