@@ -226,17 +226,18 @@ PyErr_ExceptionMatches(PyObject *exc)
226
226
void
227
227
PyErr_NormalizeException (PyObject * * exc , PyObject * * val , PyObject * * tb )
228
228
{
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 ;
234
232
233
+ restart :
234
+ type = * exc ;
235
235
if (type == NULL ) {
236
236
/* There was no exception, so nothing to do. */
237
237
return ;
238
238
}
239
239
240
+ value = * val ;
240
241
/* If PyErr_SetNone() was used, the value will have been actually
241
242
set to NULL.
242
243
*/
@@ -245,14 +246,18 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
245
246
Py_INCREF (value );
246
247
}
247
248
248
- if (PyExceptionInstance_Check (value ))
249
- inclass = PyExceptionInstance_Class (value );
250
-
251
249
/* Normalize the exception so that if the type is a class, the
252
250
value will be an instance.
253
251
*/
254
252
if (PyExceptionClass_Check (type )) {
253
+ PyObject * inclass ;
255
254
int is_subclass ;
255
+
256
+ if (PyExceptionInstance_Check (value ))
257
+ inclass = PyExceptionInstance_Class (value );
258
+ else
259
+ inclass = NULL ;
260
+
256
261
if (inclass ) {
257
262
is_subclass = PyObject_IsSubclass (inclass , type );
258
263
if (is_subclass < 0 )
@@ -266,7 +271,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
266
271
value as an argument to instantiation of the type
267
272
class.
268
273
*/
269
- if (!inclass || ! is_subclass ) {
274
+ if (!is_subclass ) {
270
275
PyObject * fixed_value ;
271
276
272
277
fixed_value = _PyErr_CreateException (type , value );
@@ -289,6 +294,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
289
294
* exc = type ;
290
295
* val = value ;
291
296
return ;
297
+
292
298
finally :
293
299
Py_DECREF (type );
294
300
Py_DECREF (value );
@@ -298,6 +304,7 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
298
304
*/
299
305
initial_tb = * tb ;
300
306
PyErr_Fetch (exc , val , tb );
307
+ assert (* exc != NULL );
301
308
if (initial_tb != NULL ) {
302
309
if (* tb == NULL )
303
310
* tb = initial_tb ;
@@ -306,18 +313,17 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
306
313
}
307
314
/* normalize recursively */
308
315
tstate = PyThreadState_GET ();
309
- if (++ tstate -> recursion_depth > Py_GetRecursionLimit ()) {
310
- -- tstate -> recursion_depth ;
316
+ if (++ recursion_depth > Py_GetRecursionLimit () - tstate -> recursion_depth ) {
311
317
/* throw away the old exception and use the recursion error instead */
312
318
Py_INCREF (PyExc_RecursionError );
313
319
Py_SETREF (* exc , PyExc_RecursionError );
314
320
Py_INCREF (PyExc_RecursionErrorInst );
315
- Py_SETREF (* val , PyExc_RecursionErrorInst );
321
+ Py_XSETREF (* val , PyExc_RecursionErrorInst );
316
322
/* just keeping the old traceback */
317
323
return ;
318
324
}
319
- PyErr_NormalizeException ( exc , val , tb );
320
- -- tstate -> recursion_depth ;
325
+ /* eliminate tail recursion */
326
+ goto restart ;
321
327
}
322
328
323
329
0 commit comments