[Python-checkins] cpython: Issue #18408: PyEval_EvalFrameEx() and PyEval_CallObjectWithKeywords() now fail

victor.stinner python-checkins at python.org
Thu Jul 18 01:46:23 CEST 2013


http://hg.python.org/cpython/rev/48a869a39e2d
changeset:   84704:48a869a39e2d
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Thu Jul 18 01:41:08 2013 +0200
summary:
  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.

files:
  Modules/_io/bufferedio.c |   5 +++++
  Python/ceval.c           |  26 ++++++++++++++++++++++++++
  Python/errors.c          |  11 +++++++++++
  3 files changed, 42 insertions(+), 0 deletions(-)


diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -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 --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -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 --git a/Python/errors.c b/Python/errors.c
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -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);

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list