From 9263f5797c41dd3c781913ee827992c3686ac8a3 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Fri, 27 Jun 2003 16:13:17 +0000 Subject: 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. --- Modules/pyexpat.c | 63 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 0f6608a..5a8423e 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -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); -- cgit v0.12