Fix several bugs in handling of exceptions with trace function enabled.

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.
This commit is contained in:
Jeremy Hylton 2003-06-27 16:13:17 +00:00
parent 8f6c7c5d5f
commit 9263f5797c
1 changed files with 48 additions and 15 deletions

View 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);