Skip to content
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

gh-58933: Make pdb return to caller frame correctly when f_trace is not set #118979

Merged
merged 2 commits into from
May 13, 2024
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
16 changes: 9 additions & 7 deletions Lib/bdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ def dispatch_return(self, frame, arg):
# The user issued a 'next' or 'until' command.
if self.stopframe is frame and self.stoplineno != -1:
self._set_stopinfo(None, None)
# The previous frame might not have f_trace set, unless we are
# issuing a command that does not expect to stop, we should set
# f_trace
if self.stoplineno != -1:
self._set_caller_tracefunc(frame)
return self.trace_dispatch

def dispatch_exception(self, frame, arg):
Expand Down Expand Up @@ -320,15 +325,14 @@ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0, opcode=False):
self.stoplineno = stoplineno
self._set_trace_opcodes(opcode)

def _set_caller_tracefunc(self):
def _set_caller_tracefunc(self, current_frame):
# Issue #13183: pdb skips frames after hitting a breakpoint and running
# step commands.
# Restore the trace function in the caller (that may not have been set
# for performance reasons) when returning from the current frame.
if self.frame_returning:
caller_frame = self.frame_returning.f_back
if caller_frame and not caller_frame.f_trace:
caller_frame.f_trace = self.trace_dispatch
caller_frame = current_frame.f_back
if caller_frame and not caller_frame.f_trace:
caller_frame.f_trace = self.trace_dispatch

# Derived classes and clients can call the following methods
# to affect the stepping state.
Expand All @@ -343,12 +347,10 @@ def set_until(self, frame, lineno=None):

def set_step(self):
"""Stop after one line of code."""
self._set_caller_tracefunc()
self._set_stopinfo(None, None)

def set_stepinstr(self):
"""Stop before the next instruction."""
self._set_caller_tracefunc()
self._set_stopinfo(None, None, opcode=True)

def set_next(self, frame):
Expand Down
52 changes: 52 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1453,6 +1453,58 @@ def test_post_mortem():
"""


def test_pdb_return_to_different_file():
"""When pdb returns to a different file, it should not skip if f_trace is
not already set

>>> import pprint

>>> class A:
... def __repr__(self):
... return 'A'

>>> def test_function():
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
... pprint.pprint(A())

>>> reset_Breakpoint()
>>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
... 'b A.__repr__',
... 'continue',
... 'return',
... 'next',
... 'return',
... 'return',
... 'continue',
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_return_to_different_file[2]>(2)test_function()
-> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
(Pdb) b A.__repr__
Breakpoint 1 at <doctest test.test_pdb.test_pdb_return_to_different_file[1]>:3
(Pdb) continue
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()
-> return 'A'
(Pdb) return
--Return--
> <doctest test.test_pdb.test_pdb_return_to_different_file[1]>(3)__repr__()->'A'
-> return 'A'
(Pdb) next
> ...pprint.py..._safe_repr()
-> return rep,...
(Pdb) return
--Return--
> ...pprint.py..._safe_repr()->('A'...)
-> return rep,...
(Pdb) return
--Return--
> ...pprint.py...format()->('A'...)
-> return...
(Pdb) continue
A
"""


def test_pdb_skip_modules():
"""This illustrates the simple case of module skipping.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make :mod:`pdb` return to caller frame correctly when ``f_trace`` of the caller frame is not set
Loading