(original) (raw)

changeset: 84704:48a869a39e2d user: Victor Stinner victor.stinner@gmail.com date: Thu Jul 18 01:41:08 2013 +0200 files: Modules/_io/bufferedio.c Python/ceval.c Python/errors.c description: 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. diff -r a2214ab0812e -r 48a869a39e2d Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c Thu Jul 18 01:42:04 2013 +0200 +++ b/Modules/_io/bufferedio.c Thu Jul 18 01:41:08 2013 +0200 @@ -663,6 +663,11 @@ _set_BlockingIOError(char *msg, Py_ssize_t written) { 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", errno, msg, written); if (err) diff -r a2214ab0812e -r 48a869a39e2d Python/ceval.c --- a/Python/ceval.c Thu Jul 18 01:42:04 2013 +0200 +++ b/Python/ceval.c Thu Jul 18 01:41:08 2013 +0200 @@ -1203,6 +1203,13 @@ if (throwflag) /* support for generator.throw() */ 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 (;;) { #ifdef WITH_TSC if (inst1 == 0) { @@ -1223,6 +1230,7 @@ #endif assert(stack_pointer >= f->f_valuestack); /* else underflow */ assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ + assert(!PyErr_Occurred()); /* Do periodic things. Doing this every time through the loop would add too much overhead, so we do it @@ -3125,6 +3133,8 @@ break; READ_TIMESTAMP(loop1); + assert(!PyErr_Occurred()); + } /* main loop */ assert(why != WHY_YIELD); @@ -3137,6 +3147,9 @@ if (why != WHY_RETURN) retval = NULL; + assert((retval != NULL && !PyErr_Occurred()) + || (retval == NULL && PyErr_Occurred())); + fast_yield: 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 @@ -4044,6 +4057,13 @@ { 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) { arg = PyTuple_New(0); if (arg == NULL) @@ -4066,6 +4086,9 @@ result = PyObject_Call(func, arg, kw); Py_DECREF(arg); + + assert((result != NULL && !PyErr_Occurred()) + || (result == NULL && PyErr_Occurred())); return result; } @@ -4228,6 +4251,9 @@ Py_DECREF(w); PCALL(PCALL_POP); } + + assert((x != NULL && !PyErr_Occurred()) + || (x == NULL && PyErr_Occurred())); return x; } diff -r a2214ab0812e -r 48a869a39e2d Python/errors.c --- a/Python/errors.c Thu Jul 18 01:42:04 2013 +0200 +++ b/Python/errors.c Thu Jul 18 01:41:08 2013 +0200 @@ -71,6 +71,11 @@ if (value == NULL || !PyExceptionInstance_Check(value)) { /* We must normalize the value right now */ 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) args = PyTuple_New(0); else if (PyTuple_Check(value)) { @@ -707,6 +712,12 @@ va_start(vargs); #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); PyErr_SetObject(exception, string); Py_XDECREF(string); /victor.stinner@gmail.com