New submission from Aldo Cortesi:

I rely heavily on a code coverage analysis engine I developed, and a bug
in Python's trace functionality has been bothering me for years. Today I
snapped, and finally tracked it down to a minimal test case. To see the
problem, play with the following code:

import sys

def run(): yield 1

def trace(frame, event, arg):
    try:
        for i in []: pass
    except Exception, e:
        pass

sys.settrace(trace)
x = run()
del x

Remove the try clause, and re-run with a debug build of the interpreter
for a different symptom. Add a print statement at the end to verify that
the problem occurs when the generator object is deleted.

The problem occurs due to an interaction between generators and the
trace functionality. When a generator is deleted, the gen_del function
calls gen_close, which then sets a GeneratorExit exception. Eventually,
PyEval_EvalFrameEx is called, with the throwflag set. At this point the
trace function is called, the GeneratorExit exception which is set
causes problems with the FOR_ITER opcode, which then fails.

The attached patch against trunk fixes this by storing exceptions before
the call trace function is called, and restoring the exception
afterwards. All regression tests pass for me with this patch applied.

----------
components: Interpreter Core
files: generator-trace.patch
messages: 57598
nosy: cortesi
severity: major
status: open
title: Generators break trace functionality
type: behavior
versions: Python 2.5, Python 2.6
Added file: http://bugs.python.org/file8765/generator-trace.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1454>
__________________________________
Index: Python/ceval.c
===================================================================
--- Python/ceval.c	(revision 59033)
+++ Python/ceval.c	(working copy)
@@ -530,6 +530,7 @@
 	register PyObject *t;
 	register PyObject *stream = NULL;    /* for PRINT opcodes */
 	register PyObject **fastlocals, **freevars;
+	PyObject *error_type, *error_value, *error_traceback;
 	PyObject *retval = NULL;	/* Return value */
 	PyThreadState *tstate = PyThreadState_GET();
 	PyCodeObject *co;
@@ -700,6 +701,8 @@
 	tstate->frame = f;
 
 	if (tstate->use_tracing) {
+		PyErr_Fetch(&error_type, &error_value, &error_traceback);
+		PyErr_Clear();
 		if (tstate->c_tracefunc != NULL) {
 			/* tstate->c_tracefunc, if defined, is a
 			   function that will be called on *every* entry
@@ -731,6 +734,7 @@
 				goto exit_eval_frame;
 			}
 		}
+		PyErr_Restore(error_type, error_value, error_traceback);
 	}
 
 	co = f->f_code;
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to