8000 gh-65052: Prevent pdb from crashing when trying to display objects (#… · python/cpython@c523ce0 · GitHub
[go: up one dir, main page]

Skip to content

Commit c523ce0

Browse files
gh-65052: Prevent pdb from crashing when trying to display objects (#110578)
1 parent de956b2 commit c523ce0

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
@@ -431,8 +431,9 @@ def preloop(self):
431431
# fields are changed to be displayed
432432
if newvalue is not oldvalue and newvalue != oldvalue:
433433
displaying[expr] = newvalue
434-
self.message('display %s: %r [old: %r]' %
435-
(expr, newvalue, oldvalue))
434+
self.message('display %s: %s [old: %s]' %
435+
(expr, self._safe_repr(newvalue, expr),
436+
self._safe_repr(oldvalue, expr)))
436437

437438
def _get_tb_and_exceptions(self, tb_or_exc):
438439
"""
@@ -1460,7 +1461,7 @@ def do_args(self, arg):
14601461
for i in range(n):
14611462
name = co.co_varnames[i]
14621463
if name in dict:
1463-
self.message('%s = %r' % (name, dict[name]))
1464+
self.message('%s = %s' % (name, self._safe_repr(dict[name], name)))
14641465
else:
14651466
self.message('%s = *** undefined ***' % (name,))
14661467
do_a = do_args
@@ -1474,7 +1475,7 @@ def do_retval(self, arg):
14741475
self._print_invalid_arg(arg)
14751476
return
14761477
if '__return__' in self.curframe_locals:
1477-
self.message(repr(self.curframe_locals['__return__']))
1478+
self.message(self._safe_repr(self.curframe_locals['__return__'], "retval"))
14781479
else:
14791480
self.error('Not yet returned!')
14801481
do_rv = do_retval
@@ -1509,6 +1510,12 @@ def _msg_val_func(self, arg, func):
15091510
except:
15101511
self._error_exc()
15111512

1513+
def _safe_repr(self, obj, expr):
1514+
try:
1515+
return repr(obj)
1516+
except Exception as e:
1517+
return _rstr(f"*** repr({expr}) failed: {self._format_exc(e)} ***")
1518+
15121519
def do_p(self, arg):
15131520
"""p expression
15141521
@@ -1688,8 +1695,8 @@ def do_display(self, arg):
16881695
if not arg:
16891696
if self.displaying:
16901697
self.message('Currently displaying:')
1691-
for item in self.displaying.get(self.curframe, {}).items():
1692-
self.message('%s: %r' % item)
1698+
for key, val in self.displaying.get(self.curframe, {}).items():
1699+
self.message('%s: %s' % (key, self._safe_repr(val, key)))
16931700
else:
16941701
self.message('No expression is being displayed')
16951702
else:
@@ -1698,7 +1705,7 @@ def do_display(self, arg):
16981705
else:
16991706
val = self._getval_except(arg)
17001707
self.displaying.setdefault(self.curframe, {})[arg] = val
1701-
self.message('display %s: %r' % (arg, val))
1708+
self.message('display %s: %s' % (arg, self._safe_repr(val, arg)))
17021709

17031710
complete_display = _complete_expression
17041711

Lib/test/test_pdb.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,6 +2350,53 @@ def test_pdb_ambiguous_statements():
23502350
(Pdb) continue
23512351
"""
23522352

2353+
def test_pdb_issue_gh_65052():
2354+
"""See GH-65052
2355+
2356+
args, retval and display should not crash if the object is not displayable
2357+
>>> class A:
2358+
... def __new__(cls):
2359+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2360+
... return object.__new__(cls)
2361+
... def __init__(self):
2362+
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
2363+
... self.a = 1
2364+
... def __repr__(self):
2365+
... return self.a
2366+
2367+
>>> def test_function():
2368+
... A()
2369+
>>> with PdbTestInput([ # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
2370+
... 's',
2371+
... 'retval',
2372+
... 'continue',
2373+
... 'args',
2374+
... 'display self',
2375+
... 'display',
2376+
... 'continue',
2377+
... ]):
2378+
... test_function()
2379+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()
2380+
-> return object.__new__(cls)
2381+
(Pdb) s
2382+
--Return--
2383+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(4)__new__()-><A instance at ...>
2384+
-> return object.__new__(cls)
2385+
(Pdb) retval
2386+
*** repr(retval) failed: AttributeError: 'A' object has no attribute 'a' ***
2387+
(Pdb) continue
2388+
> <doctest test.test_pdb.test_pdb_issue_gh_65052[0]>(7)__init__()
2389+
-> self.a = 1
2390+
(Pdb) args
2391+
self = *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
2392+
(Pdb) display self
2393+
display self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
2394+
(Pdb) display
2395+
Currently displaying:
2396+
self: *** repr(self) failed: AttributeError: 'A' object has no attribute 'a' ***
2397+
(Pdb) continue
2398+
"""
2399+
23532400

23542401
@support.requires_subprocess()
23552402
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