Kaydet (Commit) ace47d7e authored tarafından Victor Stinner's avatar Victor Stinner

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.
üst e9af4cfa
...@@ -663,6 +663,11 @@ static void ...@@ -663,6 +663,11 @@ static void
_set_BlockingIOError(char *msg, Py_ssize_t written) _set_BlockingIOError(char *msg, Py_ssize_t written)
{ {
PyObject *err; PyObject *err;
#ifdef Py_DEBUG
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion error
if an exception is set when it is called */
PyErr_Clear();
#endif
err = PyObject_CallFunction(PyExc_BlockingIOError, "isn", err = PyObject_CallFunction(PyExc_BlockingIOError, "isn",
errno, msg, written); errno, msg, written);
if (err) if (err)
......
...@@ -1203,6 +1203,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1203,6 +1203,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (throwflag) /* support for generator.throw() */ if (throwflag) /* support for generator.throw() */
goto error; goto error;
#ifdef Py_DEBUG
/* PyEval_EvalFrameEx() must not be called with an exception set,
because it may clear it (directly or indirectly) and so the
caller looses its exception */
assert(!PyErr_Occurred());
#endif
for (;;) { for (;;) {
#ifdef WITH_TSC #ifdef WITH_TSC
if (inst1 == 0) { if (inst1 == 0) {
...@@ -1223,6 +1230,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1223,6 +1230,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#endif #endif
assert(stack_pointer >= f->f_valuestack); /* else underflow */ assert(stack_pointer >= f->f_valuestack); /* else underflow */
assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */
assert(!PyErr_Occurred());
/* Do periodic things. Doing this every time through /* Do periodic things. Doing this every time through
the loop would add too much overhead, so we do it the loop would add too much overhead, so we do it
...@@ -3125,6 +3133,8 @@ fast_block_end: ...@@ -3125,6 +3133,8 @@ fast_block_end:
break; break;
READ_TIMESTAMP(loop1); READ_TIMESTAMP(loop1);
assert(!PyErr_Occurred());
} /* main loop */ } /* main loop */
assert(why != WHY_YIELD); assert(why != WHY_YIELD);
...@@ -3137,6 +3147,9 @@ fast_block_end: ...@@ -3137,6 +3147,9 @@ fast_block_end:
if (why != WHY_RETURN) if (why != WHY_RETURN)
retval = NULL; retval = NULL;
assert((retval != NULL && !PyErr_Occurred())
|| (retval == NULL && PyErr_Occurred()));
fast_yield: fast_yield:
if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) { if (co->co_flags & CO_GENERATOR && (why == WHY_YIELD || why == WHY_RETURN)) {
/* The purpose of this block is to put aside the generator's exception /* 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) ...@@ -4044,6 +4057,13 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
{ {
PyObject *result; PyObject *result;
#ifdef Py_DEBUG
/* PyEval_CallObjectWithKeywords() must not be called with an exception
set, because it may clear it (directly or indirectly)
and so the caller looses its exception */
assert(!PyErr_Occurred());
#endif
if (arg == NULL) { if (arg == NULL) {
arg = PyTuple_New(0); arg = PyTuple_New(0);
if (arg == NULL) if (arg == NULL)
...@@ -4066,6 +4086,9 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw) ...@@ -4066,6 +4086,9 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
result = PyObject_Call(func, arg, kw); result = PyObject_Call(func, arg, kw);
Py_DECREF(arg); Py_DECREF(arg);
assert((result != NULL && !PyErr_Occurred())
|| (result == NULL && PyErr_Occurred()));
return result; return result;
} }
...@@ -4228,6 +4251,9 @@ call_function(PyObject ***pp_stack, int oparg ...@@ -4228,6 +4251,9 @@ call_function(PyObject ***pp_stack, int oparg
Py_DECREF(w); Py_DECREF(w);
PCALL(PCALL_POP); PCALL(PCALL_POP);
} }
assert((x != NULL && !PyErr_Occurred())
|| (x == NULL && PyErr_Occurred()));
return x; return x;
} }
......
...@@ -71,6 +71,11 @@ PyErr_SetObject(PyObject *exception, PyObject *value) ...@@ -71,6 +71,11 @@ PyErr_SetObject(PyObject *exception, PyObject *value)
if (value == NULL || !PyExceptionInstance_Check(value)) { if (value == NULL || !PyExceptionInstance_Check(value)) {
/* We must normalize the value right now */ /* We must normalize the value right now */
PyObject *args, *fixed_value; PyObject *args, *fixed_value;
#ifdef Py_DEBUG
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion
error if an exception is set when it is called */
PyErr_Clear();
#endif
if (value == NULL || value == Py_None) if (value == NULL || value == Py_None)
args = PyTuple_New(0); args = PyTuple_New(0);
else if (PyTuple_Check(value)) { else if (PyTuple_Check(value)) {
...@@ -707,6 +712,12 @@ PyErr_Format(PyObject *exception, const char *format, ...) ...@@ -707,6 +712,12 @@ PyErr_Format(PyObject *exception, const char *format, ...)
va_start(vargs); va_start(vargs);
#endif #endif
#ifdef Py_DEBUG
/* in debug mode, PyEval_EvalFrameEx() fails with an assertion error
if an exception is set when it is called */
PyErr_Clear();
#endif
string = PyUnicode_FromFormatV(format, vargs); string = PyUnicode_FromFormatV(format, vargs);
PyErr_SetObject(exception, string); PyErr_SetObject(exception, string);
Py_XDECREF(string); Py_XDECREF(string);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment