]> granicus.if.org Git - python/commitdiff
Fix several bugs in handling of exceptions with trace function enabled.
authorJeremy Hylton <jeremy@alum.mit.edu>
Fri, 27 Jun 2003 16:13:17 +0000 (16:13 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Fri, 27 Jun 2003 16:13:17 +0000 (16:13 +0000)
If the callback raised an exception but did not set curexc_traceback,
the trace function was called with PyTrace_RETURN.  That is, the trace
function was called with an exception set.  The main loop detected the
exception when the trace function returned; it complained and disabled
tracing.

Fix the logic error so that PyTrace_RETURN only occurs if the callback
returned normally.

The trace function must be called for exceptions, too.  So we had
to add new functionality to call with PyTrace_EXCEPTION.  (Leads to a
rather ugly ifdef / else block that contains only a '}'.)

Reverse the logic and name of NOFIX_TRACE to FIX_TRACE.

Joint work with Fred.

Modules/pyexpat.c

index 0f6608a6f96c2169848e180bd4e6a6b58ad99708..5a8423e0248af581feaf4503ee8a0c828bef8500 100644 (file)
@@ -24,7 +24,8 @@
 #if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 2)
 /* In Python 2.0 and  2.1, disabling Unicode was not possible. */
 #define Py_USING_UNICODE
-#define NOFIX_TRACE
+#else
+#define FIX_TRACE
 #endif
 
 enum HandlerTypes {
@@ -293,7 +294,7 @@ getcode(enum HandlerTypes slot, char* func_name, int lineno)
     return NULL;
 }
 
-#ifndef NOFIX_TRACE
+#ifdef FIX_TRACE
 static int
 trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val)
 {
@@ -320,6 +321,37 @@ trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val)
     }  
     return result;
 }
+
+static int
+trace_frame_exc(PyThreadState *tstate, PyFrameObject *f)
+{
+    PyObject *type, *value, *traceback, *arg;
+    int err;
+
+    if (tstate->c_tracefunc == NULL)
+       return 0;
+
+    PyErr_Fetch(&type, &value, &traceback);
+    if (value == NULL) {
+       value = Py_None;
+       Py_INCREF(value);
+    }
+    arg = Py_BuildValue("(OOO)", type, value, traceback);
+    if (arg == NULL) {
+       PyErr_Restore(type, value, traceback);
+       return 0;
+    }
+    err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg);
+    Py_DECREF(arg);
+    if (err == 0)
+       PyErr_Restore(type, value, traceback);
+    else {
+       Py_XDECREF(type);
+       Py_XDECREF(value);
+       Py_XDECREF(traceback);
+    }
+    return err;
+}
 #endif
 
 static PyObject*
@@ -332,31 +364,32 @@ call_with_frame(PyCodeObject *c, PyObject* func, PyObject* args)
     if (c == NULL)
         return NULL;
     
-    f = PyFrame_New(
-                    tstate,                    /*back*/
-                    c,                         /*code*/
-                    PyEval_GetGlobals(),       /*globals*/
-                    NULL                       /*locals*/
-                    );
+    f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL);
     if (f == NULL)
         return NULL;
     tstate->frame = f;
-#ifndef NOFIX_TRACE
-    if (trace_frame(tstate, f, PyTrace_CALL, Py_None)) {
-       Py_DECREF(f);
+#ifdef FIX_TRACE
+    if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) {
        return NULL;
     }
 #endif
     res = PyEval_CallObject(func, args);
-    if (res == NULL && tstate->curexc_traceback == NULL)
-        PyTraceBack_Here(f);
-#ifndef NOFIX_TRACE
+    if (res == NULL) {
+       if (tstate->curexc_traceback == NULL)
+           PyTraceBack_Here(f);
+#ifdef FIX_TRACE
+       if (trace_frame_exc(tstate, f) < 0) {
+           return NULL;
+       }
+    }
     else {
-       if (trace_frame(tstate, f, PyTrace_RETURN, res)) {
+       if (trace_frame(tstate, f, PyTrace_RETURN, res) < 0) {
            Py_XDECREF(res);
            res = NULL;
        }
     }
+#else
+    }
 #endif
     tstate->frame = f->f_back;
     Py_DECREF(f);