Skip to content

Commit ee64b1c

Browse files
committed
Import _PyErr_NormalizeException from CPython
1 parent 7cb38ae commit ee64b1c

File tree

1 file changed

+102
-4
lines changed
  • graalpython/com.oracle.graal.python.cext/src

1 file changed

+102
-4
lines changed

graalpython/com.oracle.graal.python.cext/src/errors.c

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
#include "capi.h" // GraalPy change
1010
#include "Python.h"
11-
#if 0 // GraalPy change
1211
#include "pycore_call.h" // _PyObject_CallNoArgs()
12+
#if 0 // GraalPy change
1313
#include "pycore_initconfig.h" // _PyStatus_ERR()
1414
#endif // GraalPy change
1515
#include "pycore_pyerrors.h" // _PyErr_Format()
@@ -68,6 +68,7 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
6868
}
6969
return exc_info;
7070
}
71+
#endif // GraalPy change
7172

7273
static PyObject*
7374
_PyErr_CreateException(PyObject *exception_type, PyObject *value)
@@ -94,7 +95,6 @@ _PyErr_CreateException(PyObject *exception_type, PyObject *value)
9495

9596
return exc;
9697
}
97-
#endif // GraalPy change
9898

9999
void
100100
_PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
@@ -234,9 +234,107 @@ void
234234
_PyErr_NormalizeException(PyThreadState *tstate, PyObject **exc,
235235
PyObject **val, PyObject **tb)
236236
{
237-
// GraalPy change: nothing to do here from our side, the exception is already
238-
// reified
237+
int recursion_depth = 0;
238+
// GraalPy change: we don't have recursion_headroom
239+
// tstate->recursion_headroom++;
240+
PyObject *type, *value, *initial_tb;
241+
242+
restart:
243+
type = *exc;
244+
if (type == NULL) {
245+
/* There was no exception, so nothing to do. */
246+
// tstate->recursion_headroom--;
247+
return;
248+
}
249+
250+
value = *val;
251+
/* If PyErr_SetNone() was used, the value will have been actually
252+
set to NULL.
253+
*/
254+
if (!value) {
255+
value = Py_None;
256+
Py_INCREF(value);
257+
}
258+
259+
/* Normalize the exception so that if the type is a class, the
260+
value will be an instance.
261+
*/
262+
if (PyExceptionClass_Check(type)) {
263+
PyObject *inclass = NULL;
264+
int is_subclass = 0;
265+
266+
if (PyExceptionInstance_Check(value)) {
267+
inclass = PyExceptionInstance_Class(value);
268+
is_subclass = PyObject_IsSubclass(inclass, type);
269+
if (is_subclass < 0) {
270+
goto error;
271+
}
272+
}
273+
274+
/* If the value was not an instance, or is not an instance
275+
whose class is (or is derived from) type, then use the
276+
value as an argument to instantiation of the type
277+
class.
278+
*/
279+
if (!is_subclass) {
280+
PyObject *fixed_value = _PyErr_CreateException(type, value);
281+
if (fixed_value == NULL) {
282+
goto error;
283+
}
284+
Py_DECREF(value);
285+
value = fixed_value;
286+
}
287+
/* If the class of the instance doesn't exactly match the
288+
class of the type, believe the instance.
289+
*/
290+
else if (inclass != type) {
291+
Py_INCREF(inclass);
292+
Py_DECREF(type);
293+
type = inclass;
294+
}
295+
}
296+
*exc = type;
297+
*val = value;
298+
// tstate->recursion_headroom--;
239299
return;
300+
301+
error:
302+
Py_DECREF(type);
303+
Py_DECREF(value);
304+
recursion_depth++;
305+
if (recursion_depth == Py_NORMALIZE_RECURSION_LIMIT) {
306+
_PyErr_SetString(tstate, PyExc_RecursionError,
307+
"maximum recursion depth exceeded "
308+
"while normalizing an exception");
309+
}
310+
/* If the new exception doesn't set a traceback and the old
311+
exception had a traceback, use the old traceback for the
312+
new exception. It's better than nothing.
313+
*/
314+
initial_tb = *tb;
315+
_PyErr_Fetch(tstate, exc, val, tb);
316+
assert(*exc != NULL);
317+
if (initial_tb != NULL) {
318+
if (*tb == NULL)
319+
*tb = initial_tb;
320+
else
321+
Py_DECREF(initial_tb);
322+
}
323+
/* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded, and the
324+
corresponding RecursionError could not be normalized, and the
325+
MemoryError raised when normalize this RecursionError could not be
326+
normalized. */
327+
if (recursion_depth >= Py_NORMALIZE_RECURSION_LIMIT + 2) {
328+
if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) {
329+
Py_FatalError("Cannot recover from MemoryErrors "
330+
"while normalizing exceptions.");
331+
}
332+
else {
333+
Py_FatalError("Cannot recover from the recursive normalization "
334+
"of an exception.");
335+
}
336+
}
337+
goto restart;
240338
}
241339

242340

0 commit comments

Comments
 (0)