diff --git a/code_data/blocks.py b/code_data/blocks.py index 129652b..e33de7e 100644 --- a/code_data/blocks.py +++ b/code_data/blocks.py @@ -5,6 +5,7 @@ from __future__ import annotations +import ctypes import dis import sys from dataclasses import dataclass, field @@ -61,7 +62,6 @@ def bytes_to_blocks(b: bytes) -> Blocks: # Compute a sorted list of target, to map each one to a bloc offset targets = sorted(targets_set) del targets_set - # Then, iterate through each instruction to update the jump to point to the # block offset, instead of the bytecode offset block: list[Instruction] @@ -232,6 +232,9 @@ def _parse_bytes(b: bytes) -> Iterable[tuple[int, int, int, int, int]]: n_args += 1 if opcode == dis.EXTENDED_ARG: arg = arg << 8 + # https://github.com/python/cpython/pull/31285 + if arg > _c_int_upper_limit: + arg -= _c_int_length else: first_offset = i - ((n_args - 1) * 2) next_offset = i + 2 @@ -248,3 +251,11 @@ def _instrsize(arg: int) -> int: From https://github.com/python/cpython/blob/b2e5794870eb4728ddfaafc0f79a40299576434f/Python/wordcode_helpers.h#L11-L20 """ return 1 if arg <= 0xFF else 2 if arg <= 0xFFFF else 3 if arg <= 0xFFFFFF else 4 + + +# The number of bits in a signed int +_c_int_bit_size = ctypes.sizeof(ctypes.c_int()) * 8 +# The maximum value that can be stored in a signed int +_c_int_upper_limit = (2 ** (_c_int_bit_size - 1)) - 1 +# The number of values that can be stored in a signed int +_c_int_length = 2 ** _c_int_bit_size diff --git a/code_data/code_data_test.py b/code_data/code_data_test.py index 0d722f7..9ca99e4 100644 --- a/code_data/code_data_test.py +++ b/code_data/code_data_test.py @@ -183,6 +183,14 @@ def main(args): ''', id="pip._vendor.pep517.build minimal", ), + pytest.param( + """while not x < y < z: + pass""", + # Reduced from imagesize module + # https://bugs.python.org/issue46724 + # negative opargs in Python 3.10 + id="bpo-46724", + ), ], ) def test_examples(source): @@ -242,7 +250,6 @@ def module_codes() -> Iterable[tuple[str, str, CodeType]]: warnings.simplefilter("ignore") for mi in pkgutil.walk_packages(onerror=lambda _name: None): loader: Loader = mi.module_finder.find_module(mi.name) # type: ignore - loader.__ne__ try: code = loader.get_code(mi.name) # type: ignore except SyntaxError: