Commit 9263f579 authored by Jeremy Hylton's avatar Jeremy Hylton

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.
parent 8f6c7c5d
......@@ -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)
if (res == NULL) {
if (tstate->curexc_traceback == NULL)
PyTraceBack_Here(f);
#ifndef NOFIX_TRACE
#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);
......
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