Commit 2e438cc2 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-34989: python-gdb.py: fix current_line_num() (GH-9889)

python-gdb.py now handles errors on computing the line number
of a Python frame.

Changes:

* PyFrameObjectPtr.current_line_num() now catchs any Exception on
  calling addr2line(), instead of failing with a surprising "<class
  'TypeError'> 'FakeRepr' object is not subscriptable" error.
* All callers of current_line_num() now handle current_line_num()
  returning None.
* PyFrameObjectPtr.current_line() now also catchs IndexError on
  getting a line from the Python source file.
parent ee171a26
python-gdb.py now handles errors on computing the line number of a Python
frame.
......@@ -934,35 +934,50 @@ class PyFrameObjectPtr(PyObjectPtr):
if long(f_trace) != 0:
# we have a non-NULL f_trace:
return self.f_lineno
else:
#try:
try:
return self.co.addr2line(self.f_lasti)
#except ValueError:
# return self.f_lineno
except Exception:
# bpo-34989: addr2line() is a complex function, it can fail in many
# ways. For example, it fails with a TypeError on "FakeRepr" if
# gdb fails to load debug symbols. Use a catch-all "except
# Exception" to make the whole function safe. The caller has to
# handle None anyway for optimized Python.
return None
def current_line(self):
'''Get the text of the current source line as a string, with a trailing
newline character'''
if self.is_optimized_out():
return '(frame information optimized out)'
lineno = self.current_line_num()
if lineno is None:
return '(failed to get frame line number)'
filename = self.filename()
try:
f = open(os_fsencode(filename), 'r')
with open(os_fsencode(filename), 'r') as fp:
lines = fp.readlines()
except IOError:
return None
with f:
all_lines = f.readlines()
# Convert from 1-based current_line_num to 0-based list offset:
return all_lines[self.current_line_num()-1]
try:
# Convert from 1-based current_line_num to 0-based list offset
return lines[lineno - 1]
except IndexError:
return None
def write_repr(self, out, visited):
if self.is_optimized_out():
out.write('(frame information optimized out)')
return
out.write('Frame 0x%x, for file %s, line %i, in %s ('
lineno = self.current_line_num()
lineno = str(lineno) if lineno is not None else "?"
out.write('Frame 0x%x, for file %s, line %s, in %s ('
% (self.as_address(),
self.co_filename.proxyval(visited),
self.current_line_num(),
lineno,
self.co_name.proxyval(visited)))
first = True
for pyop_name, pyop_value in self.iter_locals():
......@@ -981,9 +996,11 @@ class PyFrameObjectPtr(PyObjectPtr):
sys.stdout.write(' (frame information optimized out)\n')
return
visited = set()
sys.stdout.write(' File "%s", line %i, in %s\n'
lineno = self.current_line_num()
lineno = str(lineno) if lineno is not None else "?"
sys.stdout.write(' File "%s", line %s, in %s\n'
% (self.co_filename.proxyval(visited),
self.current_line_num(),
lineno,
self.co_name.proxyval(visited)))
class PySetObjectPtr(PyObjectPtr):
......@@ -1732,6 +1749,9 @@ class PyList(gdb.Command):
filename = pyop.filename()
lineno = pyop.current_line_num()
if lineno is None:
print('Unable to read python frame line number')
return
if start is None:
start = lineno - 5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment