Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ace47d7

Browse files
committed
Issue #18408: PyEval_EvalFrameEx() and PyEval_CallObjectWithKeywords() now fail
with an assertion error if they are called with an exception set (PyErr_Occurred()). If these functions are called with an exception set, the exception may be cleared and so the caller looses its exception. Add also assertions to PyEval_CallObjectWithKeywords() and call_function() to check if the function succeed with no exception set, or the function failed with an exception set.
1 parent e9af4cf commit ace47d7

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

Modules/_io/bufferedio.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,11 @@ static void
663663
_set_BlockingIOError(char *msg, Py_ssize_t written)
664664
{
665665
PyObject *err;
666+
#ifdef Py_DEBUG
667+
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion error
668+
if an exception is set when it is called */
669+
PyErr_Clear();
670+
#endif
666671
err = PyObject_CallFunction(PyExc_BlockingIOError, "isn",
667672
errno, msg, written);
668673
if (err)

Python/ceval.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
12031203
if (throwflag) /* support for generator.throw() */
12041204
goto error;
12051205

1206+
#ifdef Py_DEBUG
1207+
/* PyEval_EvalFrameEx() must not be called with an exception set,
1208+
because it may clear it (directly or indirectly) and so the
1209+
caller looses its exception */
1210+
assert(!PyErr_Occurred());
1211+
#endif
1212+
12061213
for (;;) {
12071214
#ifdef WITH_TSC
12081215
if (inst1 == 0) {
@@ -1223,6 +1230,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
12231230
#endif
12241231
assert(stack_pointer >= f->f_valuestack); /* else underflow */
12251232
assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */
1233+
assert(!PyErr_Occurred());
12261234

12271235
/* Do periodic things. Doing this every time through
12281236
the loop would add too much overhead, so we do it
@@ -3125,6 +3133,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
31253133
break;
31263134
READ_TIMESTAMP(loop1);
31273135

3136+
assert(!PyErr_Occurred());
3137+
31283138
} /* main loop */
31293139

31303140
assert(why != WHY_YIELD);
@@ -3137,6 +3147,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
31373147
if (why != WHY_RETURN)
31383148
retval = NULL;
31393149

3150+
assert((retval != NULL && !PyErr_Occurred())
3151+
|| (retval == NULL && PyErr_Occurred()));
3152+
31403153
fast_yield:
31413154
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
31423155
/* The purpose of this block is to put aside the generator's exception
@@ -4044,6 +4057,13 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
40444057
{
40454058
PyObject *result;
40464059

4060+
#ifdef Py_DEBUG
4061+
/* PyEval_CallObjectWithKeywords() must not be called with an exception
4062+
set, because it may clear it (directly or indirectly)
4063+
and so the caller looses its exception */
4064+
assert(!PyErr_Occurred());
4065+
#endif
4066+
40474067
if (arg == NULL) {
40484068
arg = PyTuple_New(0);
40494069
if (arg == NULL)
@@ -4066,6 +4086,9 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
40664086

40674087
result = PyObject_Call(func, arg, kw);
40684088
Py_DECREF(arg);
4089+
4090+
assert((result != NULL && !PyErr_Occurred())
4091+
|| (result == NULL && PyErr_Occurred()));
40694092
return result;
40704093
}
40714094

@@ -4228,6 +4251,9 @@ call_function(PyObject ***pp_stack, int oparg
42284251
Py_DECREF(w);
42294252
PCALL(PCALL_POP);
42304253
}
4254+
4255+
assert((x != NULL && !PyErr_Occurred())
4256+
|| (x == NULL && PyErr_Occurred()));
42314257
return x;
42324258
}
42334259

Python/errors.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
7171
if (value == NULL || !PyExceptionInstance_Check(value)) {
7272
/* We must normalize the value right now */
7373
PyObject *args, *fixed_value;
74+
#ifdef Py_DEBUG
75+
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion
76+
error if an exception is set when it is called */
77+
PyErr_Clear();
78+
#endif
7479
if (value == NULL || value == Py_None)
7580
args = PyTuple_New(0);
7681
else if (PyTuple_Check(value)) {
@@ -707,6 +712,12 @@ PyErr_Format(PyObject *exception, const char *format, ...)
707712
va_start(vargs);
708713
#endif
709714

715+
#ifdef Py_DEBUG
716+
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion error
717+
if an exception is set when it is called */
718+
PyErr_Clear();
719+
#endif
720+
710721
string = PyUnicode_FromFormatV(format, vargs);
711722
PyErr_SetObject(exception, string);
712723
Py_XDECREF(string);

0 commit comments

Comments
 (0)