diff options
-rw-r--r-- | Lib/test/test_trace.py | 21 | ||||
-rw-r--r-- | Python/ceval.c | 19 |
2 files changed, 31 insertions, 9 deletions
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index f973a19..21e5ca9 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -221,6 +221,27 @@ class RaisingTraceFuncTestCase(unittest.TestCase): def test_exception(self): self.run_test_for_event('exception') + def test_trash_stack(self): + def f(): + for i in range(5): + print i # line tracing will raise an exception at this line + + def g(frame, why, extra): + if (why == 'line' and + frame.f_lineno == f.func_code.co_firstlineno + 2): + raise RuntimeError, "i am crashing" + return g + + sys.settrace(g) + try: + f() + except RuntimeError: + # the test is really that this doesn't segfault: + import gc + gc.collect() + else: + self.fail("exception not propagated") + # 'Jump' tests: assigning to frame.f_lineno within a trace function # moves the execution position - it's how debuggers implement a Jump diff --git a/Python/ceval.c b/Python/ceval.c index 3ea1bdc..abefd32 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -819,18 +819,19 @@ eval_frame(PyFrameObject *f) for expository comments */ f->f_stacktop = stack_pointer; - if (maybe_call_line_trace(tstate->c_tracefunc, - tstate->c_traceobj, - f, &instr_lb, &instr_ub)) { + err = maybe_call_line_trace(tstate->c_tracefunc, + tstate->c_traceobj, + f, &instr_lb, &instr_ub); + /* Reload possibly changed frame fields */ + JUMPTO(f->f_lasti); + if (f->f_stacktop != NULL) { + stack_pointer = f->f_stacktop; + f->f_stacktop = NULL; + } + if (err) { /* trace function raised an exception */ - why = WHY_EXCEPTION; goto on_error; } - /* Reload possibly changed frame fields */ - JUMPTO(f->f_lasti); - stack_pointer = f->f_stacktop; - assert(stack_pointer != NULL); - f->f_stacktop = NULL; } /* Extract opcode and argument */ |