8000 bpo-28994: PyErr_NormalizeException() no longer use C stack for recur… · python/cpython@cf29653 · GitHub
[go: up one dir, main page]

Skip to content

Commit cf29653

Browse files
bpo-28994: PyErr_NormalizeException() no longer use C stack for recursion. (#2035)
MemoryError raised when normalizing a RecursionError raised during exception normalization now not always causes a fatal error.
1 parent 1b46131 commit cf29653

File tree

1 file changed

+33
-39
lines changed

1 file changed

+33
-39
lines changed

Python/errors.c

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -228,20 +228,20 @@ PyErr_ExceptionMatches(PyObject *exc)
228228
XXX: should PyErr_NormalizeException() also call
229229
PyException_SetTraceback() with the resulting value and tb?
230230
*/
231-
static void
232-
PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
233-
PyObject **tb, int recursion_depth)
231+
void
232+
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
234233
{
235-
PyObject *type = *exc;
236-
PyObject *value = *val;
237-
PyObject *inclass = NULL;
238-
PyObject *initial_tb = NULL;
234+
int recursion_depth = 0;
235+
PyObject *type, *value, *initial_tb;
239236

237+
restart:
238+
type = *exc;
240239
if (type == NULL) {
241240
/* There was no exception, so nothing to do. */
242241
return;
243242
}
244243

244+
value = *val;
245245
/* If PyErr_SetNone() was used, the value will have been actually
246246
set to NULL.
247247
*/
@@ -250,54 +250,52 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
250250
Py_INCREF(value);
251251
}
252252

253-
if (PyExceptionInstance_Check(value))
254-
inclass = PyExceptionInstance_Class(value);
255-
256253
/* Normalize the exception so that if the type is a class, the
257254
value will be an instance.
258255
*/
259256
if (PyExceptionClass_Check(type)) {
260-
int is_subclass;
261-
if (inclass) {
257+
PyObject *inclass = NULL;
258+
int is_subclass = 0;
259+
260+
if (PyExceptionInstance_Check(value)) {
261+
inclass = PyExceptionInstance_Class(value);
262262
is_subclass = PyObject_IsSubclass(inclass, type);
263-
if (is_subclass < 0)
264-
goto finally;
263+
if (is_subclass < 0) {
264+
goto error;
265+
}
265266
}
266-
else
267-
is_subclass = 0;
268267

269-
/* if the value was not an instance, or is not an instance
268+
/* If the value was not an instance, or is not an instance
270269
whose class is (or is derived from) type, then use the
271270
value as an argument to instantiation of the type
272271
class.
273272
*/
274-
if (!inclass || !is_subclass) {
275-
PyObject *fixed_value;
276-
277-
fixed_value = _PyErr_CreateException(type, value);
273+
if (!is_subclass) {
274+
PyObject *fixed_value = _PyErr_CreateException(type, value);
278275
if (fixed_value == NULL) {
279-
goto finally;
276+
goto error;
280277
}
281-
282278
Py_DECREF(value);
283279
value = fixed_value;
284280
}
285-
/* if the class of the instance doesn't exactly match the
286-
class of the type, believe the instance
281+
/* If the class of the instance doesn't exactly match the
282+
class of the type, believe the instance.
287283
*/
288284
else if (inclass != type) {
285+
Py_INCREF(inclass);
289286
Py_DECREF(type);
290287
type = inclass;
291-
Py_INCREF(type);
292288
}
293289
}
294290
*exc = type;
295291
*val = value;
296292
return;
297-
finally:
293+
294+
error:
298295
Py_DECREF(type);
299296
Py_DECREF(value);
300-
if (recursion_depth + 1 == Py_NORMALIZE_RECURSION_LIMIT) {
297+
recursion_depth++;
298+
if (recursion_depth == Py_NORMALIZE_RECURSION_LIMIT) {
301299
PyErr_SetString(PyExc_RecursionError, "maximum recursion depth "
302300
"exceeded while normalizing an exception");
303301
}
@@ -307,16 +305,18 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
307305
*/
308306
initial_tb = *tb;
309307
PyErr_Fetch(exc, val, tb);
308+
assert(*exc != NULL);
310309
if (initial_tb != NULL) {
311310
if (*tb == NULL)
312311
*tb = initial_tb;
313312
else
314313
Py_DECREF(initial_tb);
315314
}
316-
/* Normalize recursively.
317-
* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded and the
318-
* corresponding RecursionError could not be normalized.*/
319-
if (++recursion_depth > Py_NORMALIZE_RECURSION_LIMIT) {
315+
/* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded, and the
316+
corresponding RecursionError could not be normalized, and the
317+
MemoryError raised when normalize this RecursionError could not be
318+
normalized. */
319+
if (recursion_depth >= Py_NORMALIZE_RECURSION_LIMIT + 2) {
320320
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
321321
Py_FatalError("Cannot recover from MemoryErrors "
322322
"while normalizing exceptions.");
@@ -326,13 +326,7 @@ PyErr_NormalizeExceptionEx(PyObject **exc, PyObject **val,
326326
"of an exception.");
327327
}
328328
}
329-
PyErr_NormalizeExceptionEx(exc, val, tb, recursion_depth);
330-
}
331-
332-
void
333-
PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
334-
{
335-
PyErr_NormalizeExceptionEx(exc, val, tb, 0);
329+
goto restart;
336330
}
337331

338332

0 commit comments

Comments
 (0)
0