diff options
author | gaogaotiantian <gaogaotiantian@hotmail.com> | 2023-03-29 10:09:12 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-29 10:09:12 (GMT) |
commit | e375bff03736f809fbc234010c087ef9d7e0d384 (patch) | |
tree | b148534327f0f7f4dfc2705f85fba01974b96e22 | |
parent | d835b3f05de7e2d800138e5969eeb9656b0ed860 (diff) | |
download | cpython-e375bff03736f809fbc234010c087ef9d7e0d384.zip cpython-e375bff03736f809fbc234010c087ef9d7e0d384.tar.gz cpython-e375bff03736f809fbc234010c087ef9d7e0d384.tar.bz2 |
gh-103068: Check condition expression of breakpoints for pdb (#103069)
Co-authored-by: Ćukasz Langa <lukasz@langa.pl>
Co-authored-by: Artem Mukhin <ortem00@gmail.com>
-rwxr-xr-x | Lib/pdb.py | 38 | ||||
-rw-r--r-- | Lib/test/test_pdb.py | 18 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst | 2 |
3 files changed, 45 insertions, 13 deletions
@@ -377,8 +377,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): # stop when the debuggee is returning from such generators. prefix = 'Internal ' if (not exc_traceback and exc_type is StopIteration) else '' - self.message('%s%s' % (prefix, - traceback.format_exception_only(exc_type, exc_value)[-1].strip())) + self.message('%s%s' % (prefix, self._format_exc(exc_value))) self.interaction(frame, exc_traceback) # General interaction function @@ -399,7 +398,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): - newvalue, _ = self._getval_except(expr) + newvalue = self._getval_except(expr) # check for identity first; this prevents custom __eq__ to # be called at every loop, and also prevents instances whose # fields are changed to be displayed @@ -702,6 +701,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): if comma > 0: # parse stuff after comma: "condition" cond = arg[comma+1:].lstrip() + if err := self._compile_error_message(cond): + self.error('Invalid condition %s: %r' % (cond, err)) + return arg = arg[:comma].rstrip() # parse stuff before comma: [filename:]lineno | function colon = arg.rfind(':') @@ -887,6 +889,9 @@ class Pdb(bdb.Bdb, cmd.Cmd): args = arg.split(' ', 1) try: cond = args[1] + if err := self._compile_error_message(cond): + self.error('Invalid condition %s: %r' % (cond, err)) + return except IndexError: cond = None try: @@ -1246,16 +1251,15 @@ class Pdb(bdb.Bdb, cmd.Cmd): def _getval_except(self, arg, frame=None): try: if frame is None: - return eval(arg, self.curframe.f_globals, self.curframe_locals), None + return eval(arg, self.curframe.f_globals, self.curframe_locals) else: - return eval(arg, frame.f_globals, frame.f_locals), None + return eval(arg, frame.f_globals, frame.f_locals) except BaseException as exc: - err = traceback.format_exception_only(exc)[-1].strip() - return _rstr('** raised %s **' % err), exc + return _rstr('** raised %s **' % self._format_exc(exc)) def _error_exc(self): - exc_info = sys.exc_info()[:2] - self.error(traceback.format_exception_only(*exc_info)[-1].strip()) + exc = sys.exc_info()[1] + self.error(self._format_exc(exc)) def _msg_val_func(self, arg, func): try: @@ -1443,10 +1447,10 @@ class Pdb(bdb.Bdb, cmd.Cmd): else: self.message('No expression is being displayed') else: - val, exc = self._getval_except(arg) - if isinstance(exc, SyntaxError): - self.message('Unable to display %s: %r' % (arg, val)) + if err := self._compile_error_message(arg): + self.error('Unable to display %s: %r' % (arg, err)) else: + val = self._getval_except(arg) self.displaying.setdefault(self.curframe, {})[arg] = val self.message('display %s: %r' % (arg, val)) @@ -1647,6 +1651,16 @@ class Pdb(bdb.Bdb, cmd.Cmd): self.run(target.code) + def _format_exc(self, exc: BaseException): + return traceback.format_exception_only(exc)[-1].strip() + + def _compile_error_message(self, expr): + """Return the error message as string if compiling `expr` fails.""" + try: + compile(expr, "<stdin>", "eval") + except SyntaxError as exc: + return _rstr(self._format_exc(exc)) + return "" # Collect all command help into docstring, if not run with -OO diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ae9c5d7..de2bab4 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -240,9 +240,11 @@ def test_pdb_breakpoint_commands(): >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE ... 'break 3', + ... 'break 4, +', ... 'disable 1', ... 'ignore 1 10', ... 'condition 1 1 < 2', + ... 'condition 1 1 <', ... 'break 4', ... 'break 4', ... 'break', @@ -264,6 +266,8 @@ def test_pdb_breakpoint_commands(): ... 'commands 10', # out of range ... 'commands a', # display help ... 'commands 4', # already deleted + ... 'break 6, undefined', # condition causing `NameError` during evaluation + ... 'continue', # will stop, ignoring runtime error ... 'continue', ... ]): ... test_function() @@ -271,12 +275,16 @@ def test_pdb_breakpoint_commands(): -> print(1) (Pdb) break 3 Breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3 + (Pdb) break 4, + + *** Invalid condition +: SyntaxError: invalid syntax (Pdb) disable 1 Disabled breakpoint 1 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:3 (Pdb) ignore 1 10 Will ignore next 10 crossings of breakpoint 1. (Pdb) condition 1 1 < 2 New condition set for breakpoint 1. + (Pdb) condition 1 1 < + *** Invalid condition 1 <: SyntaxError: invalid syntax (Pdb) break 4 Breakpoint 2 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:4 (Pdb) break 4 @@ -331,8 +339,13 @@ def test_pdb_breakpoint_commands(): end (Pdb) commands 4 *** cannot set commands: Breakpoint 4 already deleted + (Pdb) break 6, undefined + Breakpoint 5 at <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>:6 (Pdb) continue 3 + > <doctest test.test_pdb.test_pdb_breakpoint_commands[0]>(6)test_function() + -> print(4) + (Pdb) continue 4 """ @@ -597,13 +610,14 @@ def test_pdb_display_command(): ... 'undisplay', ... 'display a < 1', ... 'n', + ... 'display undefined', ... 'continue', ... ]): ... test_function() > <doctest test.test_pdb.test_pdb_display_command[0]>(4)test_function() -> a = 1 (Pdb) display + - Unable to display +: ** raised SyntaxError: invalid syntax ** + *** Unable to display +: SyntaxError: invalid syntax (Pdb) display No expression is being displayed (Pdb) display a @@ -627,6 +641,8 @@ def test_pdb_display_command(): (Pdb) n > <doctest test.test_pdb.test_pdb_display_command[0]>(7)test_function() -> a = 4 + (Pdb) display undefined + display undefined: ** raised NameError: name 'undefined' is not defined ** (Pdb) continue """ diff --git a/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst b/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst new file mode 100644 index 0000000..71c142c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst @@ -0,0 +1,2 @@ +It's no longer possible to register conditional breakpoints in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. |