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.
This commit is contained in:
parent
ee171a26c1
commit
2e438cc255
|
@ -0,0 +1,2 @@
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue