diff options
author | Victor Stinner <vstinner@redhat.com> | 2018-10-15 21:19:57 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-15 21:19:57 (GMT) |
commit | 2e438cc2554495b28480a3ffe5cdf41b6ab823a0 (patch) | |
tree | 00c918509850590d1371ac31a859b961e5959a51 /Tools | |
parent | ee171a26c1169abfae534b08acc0d95c6e45a22a (diff) | |
download | cpython-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.
Diffstat (limited to 'Tools')
-rwxr-xr-x | Tools/gdb/libpython.py | 46 |
1 files changed, 33 insertions, 13 deletions
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 |