8000 [3.12] gh-65052: Prevent pdb from crashing when trying to display obj… · python/cpython@989aa44 · GitHub
[go: up one dir, main page]

Skip to content

Commit 989aa44

Browse files
[3.12] gh-65052: Prevent pdb from crashing when trying to display objects (GH-110578) (#110734)
gh-65052: Prevent pdb from crashing when trying to display objects (GH-110578) (cherry picked from commit c523ce0) Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com>
1 parent c06ac1b commit 989aa44

File tree

3 files changed

+62
-7
lines changed

3 files changed

+62
-7
lines changed

Lib/pdb.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,9 @@ def preloop(self):
410410
# fields are changed to be displayed
411411
if newvalue is not oldvalue and newvalue != oldvalue:
412412
displaying[expr] = newvalue
413-
self.message('display %s: %r [old: %r]' %
414-
(expr, newvalue, oldvalue))
413+
self.message('display %s: %s [old: %s]' %
414+
(expr, self._safe_repr(newvalue, expr),
415+
self._safe_repr(oldvalue, expr)))
415416

416417
def interaction(self, frame, traceback):
417418
# Restore the previous signal handler at the Pdb prompt.
@@ -1264,7 +1265,7 @@ def do_args(self, arg):
12641265
for i in range(n):
12651266
name = co.co_varnames[i]
12661267
if name in dict:
1267-
self.message('%s = %r' % (name, dict[name]))
1268+
self.message('%s = %s' % (name, self._safe_repr(dict[name], name)))
12681269
else:
12691270
self.message('%s = *** undefined ***' % (name,))
12701271
do_a = do_args
@@ -1275,7 +1276,7 @@ def do_retval(self, arg):
12751276
Print the return value for the last return of a function.
12761277
"""
12771278
if '__return__' in self.curframe_locals:
1278-
self.message(repr(self.curframe_locals['__return__']))
1279+
self.message(self._safe_repr(self.curframe_locals['__return__'], "retval"))
12791280
else:
12801281
self.error('Not yet returned!')
12811282
do_rv = do_retval
@@ -1310,6 +1311,12 @@ def _msg_val_func(self, arg, func):
13101311
except:
13111312
self._error_exc()
13121313

1314+
def _safe_repr(self, obj, expr):
1315+
try:
1316+
return repr(obj)
1317+
except Exception as e:
1318+
return _rstr(f"*** repr({expr}) failed: {self._format_exc(e)} ***")
1319+
13131320
def do_p(self, arg):
13141321
"""p expression
13151322
@@ -1486,8 +1493,8 @@ def do_display(self, arg):
14861493
if not arg:
14871494
if self.displaying:
14881495
self.message('Currently displaying:')
1489-
for item in self.displaying.get(self.curframe, {}).items():
1490-
self.message('%s: %r' % item)
1496+
for key, val in self.displaying.get(self.curframe, {}).items():
1497+
self.message('%s: %s' % (key, self._safe_repr(val, key)))
14911498
else:
14921499
self.message('No expression is being displayed')
14931500
else:
@@ -1496,7 +1503,7 @@ def do_display(self, arg):
14961503
else:
14971504
val = self._getval_except(arg)
14981505
self.displaying.setdefault(self.curframe, {})[arg] = val
1499-
self.message('display %s: %r' % (arg, val))
1506+
self.message('display %s: %s' % (arg, self._safe_repr(val, arg)))
15001507

15011508
complete_display = _complete_expression
15021509

Lib/test/test_pdb.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,53 @@ def test_pdb_ambiguous_statements():
18461846
(Pdb) continue
18471847
"""
18481848

1849+
def test_pdb_issue_gh_65052():
1850+
"""See GH-65052
1851+
1852+
args, retval and display should not crash if the object is not displayable
1853+
>>> class A:
1854+
... def __new__(cls):
1855+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1856+
... return object.__new__(cls)
1857+
... def __init__(self):
1858+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
1859+
... self.a = 1
1 6D40 860+
... def __repr__(self):
1861+
... return self.a
1862+
1863+
>>> def test_function():
1864+
... A()
1865+
>>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
1866+
... 's',
1867+
... 'retval',
1868+
... 'continue',
1869+
... 'args',
1870+
... 'display self',
1871+
... 'display',
1872+
... 'continue',
1873+
... ]):
1874+
... test_function()
1875+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()
1876+
-> return object.__new__(cls)
1877+
(Pdb) s
1878+
--Return--
1879+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()-><A instance at ...>
1880+
-> return object.__new__(cls)
1881+
(Pdb) retval
1882+
*** repr(retval) failed: AttributeError: 'A' object has no attribute 'a' ***
1883+
(Pdb) continue
1884+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(7)__init__()
1885+
-> self.a = 1
1886+
(Pdb) args
1887+
self = *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1888+
(Pdb) display self
1889+
display self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1890+
(Pdb) display
1891+
Currently displaying:
1892+
self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
1893+
(Pdb) continue
1894+
"""
1895+
18491896

18501897
@support.requires_subprocess()
18511898
class PdbTestCase(unittest.TestCase):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Prevent :mod:`pdb` from crashing when trying to display undisplayable objects

0 commit comments

Comments
 (0)
0