Skip to content

Commit 7df087e

Browse files
committed
Check bytecode before accepting a breakpoint in pdb
1 parent 2be2dd5 commit 7df087e

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

Lib/bdb.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ def _get_lineno(self, code, offset):
177177
return last_lineno
178178

179179

180+
def _get_executable_linenos(code):
181+
linenos = set()
182+
for _, _, lineno in code.co_lines():
183+
if lineno is not None:
184+
linenos.add(lineno)
185+
for const in code.co_consts:
186+
if hasattr(const, 'co_lines'):
187+
linenos |= _get_executable_linenos(const)
188+
return linenos
189+
190+
180191
class Bdb:
181192
"""Generic Python debugger base class.
182193
@@ -671,6 +682,15 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
671682
line = linecache.getline(filename, lineno)
672683
if not line:
673684
return 'Line %s:%d does not exist' % (filename, lineno)
685+
source = ''.join(linecache.getlines(filename))
686+
if source:
687+
try:
688+
code = compile(source, filename, 'exec')
689+
executable_lines = _get_executable_linenos(code)
690+
if executable_lines and lineno not in executable_lines:
691+
return 'Line %d has no code associated with it' % lineno
692+
except SyntaxError:
693+
pass
674694
self._add_to_breaks(filename, lineno)
675695
bp = Breakpoint(filename, lineno, temporary, cond, funcname)
676696
# After we set a new breakpoint, we need to search through all frames

Lib/test/test_pdb.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4188,6 +4188,22 @@ def test_breakpoint(self):
41884188
self.assertTrue(any("Breakpoint 1 at" in l for l in stdout.splitlines()), stdout)
41894189
self.assertTrue(all("SUCCESS" not in l for l in stdout.splitlines()), stdout)
41904190

4191+
def test_breakpoint_on_no_bytecode_line(self):
4192+
script = """
4193+
x = 1
4194+
def f():
4195+
global x # line 4: no bytecode
4196+
x = 2
4197+
f()
4198+
"""
4199+
commands = """
4200+
b 4
4201+
c
4202+
quit
4203+
"""
4204+
stdout, _ = self.run_pdb_module(script, commands)
4205+
self.assertIn('no code', '\n'.join(stdout.splitlines()))
4206+
41914207
def test_run_pdb_with_pdb(self):
41924208
commands = """
41934209
c

0 commit comments

Comments
 (0)