summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgaogaotiantian <gaogaotiantian@hotmail.com>2023-03-29 10:09:12 (GMT)
committerGitHub <noreply@github.com>2023-03-29 10:09:12 (GMT)
commite375bff03736f809fbc234010c087ef9d7e0d384 (patch)
treeb148534327f0f7f4dfc2705f85fba01974b96e22
parentd835b3f05de7e2d800138e5969eeb9656b0ed860 (diff)
downloadcpython-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-xLib/pdb.py38
-rw-r--r--Lib/test/test_pdb.py18
-rw-r--r--Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst2
3 files changed, 45 insertions, 13 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index d402de1..3a06cd0 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -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.