From 557ee34b8e7d6a050d5b9e2e803b163b14c5d861 Mon Sep 17 00:00:00 2001 From: elliot Date: Thu, 30 Jan 2025 18:32:54 -0600 Subject: [PATCH] fix co_lines parsing of co_linetable Co-authored-by: jdw170000 --- xdis/codetype/code310.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/xdis/codetype/code310.py b/xdis/codetype/code310.py index d79c4fd8..ed1edec7 100644 --- a/xdis/codetype/code310.py +++ b/xdis/codetype/code310.py @@ -163,24 +163,32 @@ def co_lines(self): either be a positive integer, or None Parsing implementation adapted from: https://github.com/python/cpython/blob/3.10/Objects/lnotab_notes.txt + The algorithm presented in the lnotab_notes.txt file is slightly inaccurate. The first linetable entry will have a line delta of 0, and should be yielded instead of skipped. + This implementation follows the lineiter definition in https://github.com/python/cpython/blob/3.10/Objects/codeobject.c#L1030. """ - line = self.co_firstlineno end_offset = 0 + line = self.co_firstlineno + # co_linetable is pairs of (offset_delta: unsigned byte, line_delta: signed byte) for offset_delta, line_delta in struct.iter_unpack('=Bb', self.co_linetable): assert isinstance(line_delta, int) assert isinstance(offset_delta, int) - if line_delta == 0: # No change to line number, just accumulate changes to end - end_offset += offset_delta - continue + start_offset = end_offset - end_offset = start_offset + offset_delta - if line_delta == -128: # No valid line number -- skip entry - continue - line += line_delta - if end_offset == start_offset: # Empty range, omit. + end_offset += offset_delta + + # line_delta of -128 signifies an instruction range that is not associated with any line + if line_delta != -128: + line += line_delta + display_line = line + else: + display_line = None + + # omit empty ranges + if start_offset == end_offset: continue - yield start_offset, end_offset, line + + yield start_offset, end_offset, display_line def encode_lineno_tab(self): """