-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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-103464: Add checks for arguments of pdb commands #103465
Changes from all commits
714f506
d31568a
1e541f8
095150d
5f70f5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -644,7 +644,7 @@ def do_commands(self, arg): | |
try: | ||
bnum = int(arg) | ||
except: | ||
self.error("Usage: commands [bnum]\n ...\n end") | ||
self._print_invalid_arg(arg) | ||
return | ||
try: | ||
self.get_bpbynumber(bnum) | ||
|
@@ -941,14 +941,22 @@ def do_ignore(self, arg): | |
condition evaluates to true. | ||
""" | ||
args = arg.split() | ||
try: | ||
count = int(args[1].strip()) | ||
except: | ||
if not args: | ||
self.error('Breakpoint number expected') | ||
return | ||
if len(args) == 1: | ||
count = 0 | ||
elif len(args) == 2: | ||
try: | ||
count = int(args[1]) | ||
except ValueError: | ||
self._print_invalid_arg(arg) | ||
return | ||
else: | ||
self._print_invalid_arg(arg) | ||
return | ||
try: | ||
bp = self.get_bpbynumber(args[0].strip()) | ||
except IndexError: | ||
self.error('Breakpoint number expected') | ||
except ValueError as err: | ||
self.error(err) | ||
else: | ||
|
@@ -1025,6 +1033,9 @@ def do_where(self, arg): | |
An arrow indicates the "current frame", which determines the | ||
context of most commands. 'bt' is an alias for this command. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
self.print_stack_trace() | ||
do_w = do_where | ||
do_bt = do_where | ||
|
@@ -1112,6 +1123,9 @@ def do_step(self, arg): | |
(either in a function that is called or in the current | ||
function). | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
self.set_step() | ||
return 1 | ||
do_s = do_step | ||
|
@@ -1122,6 +1136,9 @@ def do_next(self, arg): | |
Continue execution until the next line in the current function | ||
is reached or it returns. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
self.set_next(self.curframe) | ||
return 1 | ||
do_n = do_next | ||
|
@@ -1153,6 +1170,9 @@ def do_return(self, arg): | |
|
||
Continue execution until the current function returns. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
self.set_return(self.curframe) | ||
return 1 | ||
do_r = do_return | ||
|
@@ -1162,6 +1182,9 @@ def do_continue(self, arg): | |
|
||
Continue execution, only stop when a breakpoint is encountered. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
if not self.nosigint: | ||
try: | ||
Pdb._previous_sigint_handler = \ | ||
|
@@ -1256,6 +1279,9 @@ def do_args(self, arg): | |
|
||
Print the argument list of the current function. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
co = self.curframe.f_code | ||
dict = self.curframe_locals | ||
n = co.co_argcount + co.co_kwonlyargcount | ||
|
@@ -1274,6 +1300,9 @@ def do_retval(self, arg): | |
|
||
Print the return value for the last return of a function. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
if '__return__' in self.curframe_locals: | ||
self.message(repr(self.curframe_locals['__return__'])) | ||
else: | ||
|
@@ -1390,6 +1419,9 @@ def do_longlist(self, arg): | |
|
||
List the whole source code for the current function or frame. | ||
""" | ||
if arg: | ||
self._print_invalid_arg(arg) | ||
return | ||
filename = self.curframe.f_code.co_filename | ||
breaklist = self.get_file_breaks(filename) | ||
try: | ||
|
@@ -1570,7 +1602,9 @@ def do_unalias(self, arg): | |
Delete the specified alias. | ||
""" | ||
args = arg.split() | ||
if len(args) == 0: return | ||
if len(args) == 0: | ||
self._print_invalid_arg(arg) | ||
return | ||
if args[0] in self.aliases: | ||
del self.aliases[args[0]] | ||
|
||
|
@@ -1723,7 +1757,7 @@ def _getsourcelines(self, obj): | |
lineno = max(1, lineno) | ||
return lines, lineno | ||
|
||
def _help_message_from_doc(self, doc): | ||
def _help_message_from_doc(self, doc, usage_only=False): | ||
lines = [line.strip() for line in doc.rstrip().splitlines()] | ||
if not lines: | ||
return "No help message found." | ||
|
@@ -1739,10 +1773,24 @@ def _help_message_from_doc(self, doc): | |
elif i < usage_end: | ||
prefix = " " | ||
else: | ||
if usage_only: | ||
break | ||
prefix = "" | ||
formatted.append(indent + prefix + line) | ||
return "\n".join(formatted) | ||
|
||
def _print_invalid_arg(self, arg): | ||
"""Return the usage string for a function.""" | ||
|
||
self.error(f"Invalid argument: {arg}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe consider using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I was wrong about (Pdb) r '"'
*** Invalid argument: '\'"\''
Usage: r(eturn)
(Pdb)
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I usually use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, taking a look at the rest of the code, I realized people have different ideas about this. The current implementation contains a mix of |
||
|
||
# Yes it's a bit hacky. Get the caller name, get the method based on | ||
# that name, and get the docstring from that method. | ||
# This should NOT fail if the caller is a method of this class. | ||
doc = inspect.getdoc(getattr(self, sys._getframe(1).f_code.co_name)) | ||
if doc is not None: | ||
self.message(self._help_message_from_doc(doc, usage_only=True)) | ||
|
||
# Collect all command help into docstring, if not run with -OO | ||
|
||
if __doc__ is not None: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Provide helpful usage messages when parsing incorrect :mod:`pdb` commands. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current code uses
args[1].strip()
.Even though I don't have an example for when this would be useful, I suggest not to omit
.strip()
here to maintain consistency with the rest of the code here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
args[1].strip()
only strips spaces, whichint()
takes care of when it tries to convert the string to integer. This is redundant so I removed it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, thanks for explaining