diff --git a/Lib/bdb.py b/Lib/bdb.py --- a/Lib/bdb.py +++ b/Lib/bdb.py @@ -230,10 +230,6 @@ if not self.breaks: # no breakpoints; run without debugger overhead sys.settrace(None) - frame = sys._getframe().f_back - while frame and frame is not self.botframe: - del frame.f_trace - frame = frame.f_back def set_quit(self): self.stopframe = self.botframe diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -5,6 +5,7 @@ import sys import difflib import gc +import textwrap # A very basic example. If this fails, we're in deep trouble. def basic(): @@ -388,6 +389,34 @@ (257, 'line'), (257, 'return')]) + def test_17_backtrace_lineno(self): + # issue17277: line numbers in backtrace after removing the trace + # function. + tracer = Tracer() + sys.settrace(tracer.trace) + source = """ + def bar(): + sys.settrace(None) + + def foo(): + bar() + line_number = 7 + 1 / 0 + + foo() + """ + + lno = 0 + try: + exec(textwrap.dedent(source), globals()) + except ZeroDivisionError: + tb = sys.exc_info()[2] + while tb: + lno = tb.tb_lineno + tb = tb.tb_next + self.assertEqual(lno, 8, 'Bad line number in traceback after' + ' removing the trace function.') + class RaisingTraceFuncTestCase(unittest.TestCase): def setUp(self): diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -118,7 +118,8 @@ Py_XINCREF(frame); tb->tb_frame = frame; tb->tb_lasti = frame->f_lasti; - tb->tb_lineno = PyFrame_GetLineNumber(frame); + tb->tb_lineno = PyCode_Addr2Line(frame->f_code, + frame->f_lasti); PyObject_GC_Track(tb); } return tb;