Skip to content

Commit

Permalink
gh-94215: Add reproducer for segfault in frame_setlineno() (GH-94563)
Browse files Browse the repository at this point in the history
  • Loading branch information
tiran authored Jul 7, 2022
1 parent 8bbd70b commit de58842
Showing 1 changed file with 104 additions and 6 deletions.
110 changes: 104 additions & 6 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1407,14 +1407,82 @@ def test_pdb_issue_gh_91742():
(Pdb) continue
Author: 'pi' Version: '3.14'
"""

def test_pdb_issue_gh_94215():
"""See GH-94215
Check that frame_setlineno() does not leak references.
>>> def test_function():
... def func():
... def inner(v): pass
... inner(
... 42
... )
...
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
... func()
>>> reset_Breakpoint()
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
... 'step',
... 'next',
... 'next',
... 'jump 3',
... 'next',
... 'next',
... 'jump 3',
... 'next',
... 'next',
... 'jump 3',
... 'continue'
... ]):
... test_function()
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(9)test_function()
-> func()
(Pdb) step
--Call--
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(2)func()
-> def func():
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(3)func()
-> def inner(v): pass
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(4)func()
-> inner(
(Pdb) jump 3
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(3)func()
-> def inner(v): pass
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(4)func()
-> inner(
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(5)func()
-> 42
(Pdb) jump 3
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(3)func()
-> def inner(v): pass
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(4)func()
-> inner(
(Pdb) next
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(5)func()
-> 42
(Pdb) jump 3
> <doctest test.test_pdb.test_pdb_issue_gh_94215[0]>(3)func()
-> def inner(v): pass
(Pdb) continue
"""


@support.requires_subprocess()
class PdbTestCase(unittest.TestCase):
def tearDown(self):
os_helper.unlink(os_helper.TESTFN)

@unittest.skipIf(sys.flags.safe_path,
'PYTHONSAFEPATH changes default sys.path')
def _run_pdb(self, pdb_args, commands):
def _run_pdb(self, pdb_args, commands, expected_returncode=0):
self.addCleanup(os_helper.rmtree, '__pycache__')
cmd = [sys.executable, '-m', 'pdb'] + pdb_args
with subprocess.Popen(
Expand All @@ -1427,15 +1495,20 @@ def _run_pdb(self, pdb_args, commands):
stdout, stderr = proc.communicate(str.encode(commands))
stdout = stdout and bytes.decode(stdout)
stderr = stderr and bytes.decode(stderr)
self.assertEqual(
proc.returncode,
expected_returncode,
f"Unexpected return code\nstdout: {stdout}\nstderr: {stderr}"
)
return stdout, stderr

def run_pdb_script(self, script, commands):
def run_pdb_script(self, script, commands, expected_returncode=0):
"""Run 'script' lines with pdb and the pdb 'commands'."""
filename = 'main.py'
with open(filename, 'w') as f:
f.write(textwrap.dedent(script))
self.addCleanup(os_helper.unlink, filename)
return self._run_pdb([filename], commands)
return self._run_pdb([filename], commands, expected_returncode)

def run_pdb_module(self, script, commands):
"""Runs the script code as part of a module"""
Expand Down Expand Up @@ -1641,7 +1714,9 @@ def test_issue16180(self):
script = "def f: pass\n"
commands = ''
expected = "SyntaxError:"
stdout, stderr = self.run_pdb_script(script, commands)
stdout, stderr = self.run_pdb_script(
script, commands, expected_returncode=1
)
self.assertIn(expected, stdout,
'\n\nExpected:\n{}\nGot:\n{}\n'
'Fail to handle a syntax error in the debuggee.'
Expand Down Expand Up @@ -1804,7 +1879,9 @@ def test_module_without_a_main(self):
with open(init_file, 'w'):
pass
self.addCleanup(os_helper.rmtree, module_name)
stdout, stderr = self._run_pdb(['-m', module_name], "")
stdout, stderr = self._run_pdb(
['-m', module_name], "", expected_returncode=1
)
self.assertIn("ImportError: No module named t_main.__main__",
stdout.splitlines())

Expand All @@ -1817,7 +1894,9 @@ def test_package_without_a_main(self):
with open(modpath + '/__init__.py', 'w'):
pass
self.addCleanup(os_helper.rmtree, pkg_name)
stdout, stderr = self._run_pdb(['-m', modpath.replace('/', '.')], "")
stdout, stderr = self._run_pdb(
['-m', modpath.replace('/', '.')], "", expected_returncode=1
)
self.assertIn(
"'t_pkg.t_main' is a package and cannot be directly executed",
stdout)
Expand Down Expand Up @@ -2006,6 +2085,25 @@ def test_issue42383(self):
expected = '(Pdb) The correct file was executed'
self.assertEqual(stdout.split('\n')[6].rstrip('\r'), expected)

@unittest.skip("test crashes, see gh-94215")
def test_gh_94215_crash(self):
script = """\
def func():
def inner(v): pass
inner(
42
)
func()
"""
commands = textwrap.dedent("""
break func
continue
next
next
jump 2
""")
stdout, stderr = self.run_pdb_script(script, commands)
self.assertFalse(stderr)

class ChecklineTests(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit de58842

Please sign in to comment.