summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2018-10-15 21:19:57 (GMT)
committerGitHub <noreply@github.com>2018-10-15 21:19:57 (GMT)
commit2e438cc2554495b28480a3ffe5cdf41b6ab823a0 (patch)
tree00c918509850590d1371ac31a859b961e5959a51
parentee171a26c1169abfae534b08acc0d95c6e45a22a (diff)
downloadcpython-2e438cc2554495b28480a3ffe5cdf41b6ab823a0.zip
cpython-2e438cc2554495b28480a3ffe5cdf41b6ab823a0.tar.gz
cpython-2e438cc2554495b28480a3ffe5cdf41b6ab823a0.tar.bz2
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.
-rw-r--r--Misc/NEWS.d/next/Tools-Demos/2018-10-15-13-22-28.bpo-34989.hU4fra.rst2
-rwxr-xr-xTools/gdb/libpython.py46
2 files changed, 35 insertions, 13 deletions
diff --git a/Misc/NEWS.d/next/Tools-Demos/2018-10-15-13-22-28.bpo-34989.hU4fra.rst b/Misc/NEWS.d/next/Tools-Demos/2018-10-15-13-22-28.bpo-34989.hU4fra.rst
new file mode 100644
index 0000000..53bb425
--- /dev/null
+++ b/Misc/NEWS.d/next/Tools-Demos/2018-10-15-13-22-28.bpo-34989.hU4fra.rst
@@ -0,0 +1,2 @@
+python-gdb.py now handles errors on computing the line number of a Python
+frame.
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 27eabcb..bfaa940 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -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