Skip to content

[3.12] gh-58956: Set f_trace on frames with breakpoints after setting a new breakpoint (GH-124454) #125549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def __init__(self, skip=None):
self.breaks = {}
self.fncache = {}
self.frame_returning = None
self.enterframe = None

self._load_breaks()

Expand Down Expand Up @@ -341,6 +342,7 @@ def set_trace(self, frame=None):

If frame is not specified, debugging starts from caller's frame.
"""
sys.settrace(None)
if frame is None:
frame = sys._getframe().f_back
self.reset()
Expand Down Expand Up @@ -404,6 +406,14 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
return 'Line %s:%d does not exist' % (filename, lineno)
self._add_to_breaks(filename, lineno)
bp = Breakpoint(filename, lineno, temporary, cond, funcname)
# After we set a new breakpoint, we need to search through all frames
# and set f_trace to trace_dispatch if there could be a breakpoint in
# that frame.
frame = self.enterframe
while frame:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
while frame:
while frame is not None:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just keep the consistency because it was backported?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

if self.break_anywhere(frame):
frame.f_trace = self.trace_dispatch
frame = frame.f_back
return None

def _load_breaks(self):
Expand Down
30 changes: 30 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2371,6 +2371,36 @@ def test_issue26053(self):
self.assertRegex(res, "Restarting .* with arguments:\na b c")
self.assertRegex(res, "Restarting .* with arguments:\nd e f")

def test_issue58956(self):
# Set a breakpoint in a function that already exists on the call stack
# should enable the trace function for the frame.
script = """
import bar
def foo():
ret = bar.bar()
pass
foo()
"""
commands = """
b bar.bar
c
b main.py:5
c
p ret
quit
"""
bar = """
def bar():
return 42
"""
with open('bar.py', 'w') as f:
f.write(textwrap.dedent(bar))
self.addCleanup(os_helper.unlink, 'bar.py')
stdout, stderr = self.run_pdb_script(script, commands)
lines = stdout.splitlines()
self.assertIn('-> pass', lines)
self.assertIn('(Pdb) 42', lines)

def test_step_into_botframe(self):
# gh-125422
# pdb should not be able to step into the botframe (bdb.py)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed a bug in :mod:`pdb` where sometimes the breakpoint won't trigger if it was set on a function which is already in the call stack.
Loading