From 853b4b549dab445c1b54610e118fefaeba3f35e2 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sat, 4 Nov 2023 16:05:22 -0700 Subject: gh-111719: Add extra check for alias command (#111720) --- Doc/library/pdb.rst | 2 +- Lib/pdb.py | 33 ++++++++++++++++++---- Lib/test/test_pdb.py | 22 +++++++++++++++ .../2023-11-04-01-20-23.gh-issue-111719.fUiKBD.rst | 1 + 4 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-04-01-20-23.gh-issue-111719.fUiKBD.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 002eeef..bbc6aac 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -580,7 +580,7 @@ can be overridden by the local file. Create an alias called *name* that executes *command*. The *command* must *not* be enclosed in quotes. Replaceable parameters can be indicated by - ``%1``, ``%2``, and so on, while ``%*`` is replaced by all the parameters. + ``%1``, ``%2``, ... and ``%9``, while ``%*`` is replaced by all the parameters. If *command* is omitted, the current alias for *name* is shown. If no arguments are given, all aliases are listed. diff --git a/Lib/pdb.py b/Lib/pdb.py index dbb7f55..a4b02e0 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -597,11 +597,20 @@ class Pdb(bdb.Bdb, cmd.Cmd): args = line.split() while args[0] in self.aliases: line = self.aliases[args[0]] - ii = 1 - for tmpArg in args[1:]: - line = line.replace("%" + str(ii), - tmpArg) - ii += 1 + for idx in range(1, 10): + if f'%{idx}' in line: + if idx >= len(args): + self.error(f"Not enough arguments for alias '{args[0]}'") + # This is a no-op + return "!" + line = line.replace(f'%{idx}', args[idx]) + elif '%*' not in line: + if idx < len(args): + self.error(f"Too many arguments for alias '{args[0]}'") + # This is a no-op + return "!" + break + line = line.replace("%*", ' '.join(args[1:])) args = line.split() # split into ';;' separated commands @@ -616,6 +625,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): # Replace all the convenience variables line = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'__pdb_convenience_variables["\1"]', line) + return line def onecmd(self, line): @@ -1797,7 +1807,18 @@ class Pdb(bdb.Bdb, cmd.Cmd): else: self.error(f"Unknown alias '{args[0]}'") else: - self.aliases[args[0]] = ' '.join(args[1:]) + # Do a validation check to make sure no replaceable parameters + # are skipped if %* is not used. + alias = ' '.join(args[1:]) + if '%*' not in alias: + consecutive = True + for idx in range(1, 10): + if f'%{idx}' not in alias: + consecutive = False + if f'%{idx}' in alias and not consecutive: + self.error("Replaceable parameters must be consecutive") + return + self.aliases[args[0]] = alias def do_unalias(self, arg): """unalias name diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ff9e7c2..5508f7b 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -671,6 +671,14 @@ def test_pdb_alias_command(): ... 'pi o', ... 's', ... 'ps', + ... 'alias myp p %2', + ... 'alias myp', + ... 'alias myp p %1', + ... 'myp', + ... 'myp 1', + ... 'myp 1 2', + ... 'alias repeat_second_arg p "%* %2"', + ... 'repeat_second_arg 1 2 3', ... 'continue', ... ]): ... test_function() @@ -692,6 +700,20 @@ def test_pdb_alias_command(): (Pdb) ps self.attr1 = 10 self.attr2 = str + (Pdb) alias myp p %2 + *** Replaceable parameters must be consecutive + (Pdb) alias myp + *** Unknown alias 'myp' + (Pdb) alias myp p %1 + (Pdb) myp + *** Not enough arguments for alias 'myp' + (Pdb) myp 1 + 1 + (Pdb) myp 1 2 + *** Too many arguments for alias 'myp' + (Pdb) alias repeat_second_arg p "%* %2" + (Pdb) repeat_second_arg 1 2 3 + '1 2 3 2' (Pdb) continue """ diff --git a/Misc/NEWS.d/next/Library/2023-11-04-01-20-23.gh-issue-111719.fUiKBD.rst b/Misc/NEWS.d/next/Library/2023-11-04-01-20-23.gh-issue-111719.fUiKBD.rst new file mode 100644 index 0000000..1d3b948 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-04-01-20-23.gh-issue-111719.fUiKBD.rst @@ -0,0 +1 @@ +Add extra argument validation for ``alias`` command in :mod:`pdb` -- cgit v0.12