bpo-46724: Fix dis support for overflow args (GH-31285)

This commit is contained in:
Saul Shanabrook 2022-02-18 04:56:23 -05:00 committed by GitHub
parent 2923d87ca2
commit c3ce7781e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 5 deletions

View file

@ -515,6 +515,12 @@ def _disassemble_str(source, **kwargs):
disco = disassemble # XXX For backwards compatibility disco = disassemble # XXX For backwards compatibility
# Rely on C `int` being 32 bits for oparg
_INT_BITS = 32
# Value for c int when it overflows
_INT_OVERFLOW = 2 ** (_INT_BITS - 1)
def _unpack_opargs(code): def _unpack_opargs(code):
extended_arg = 0 extended_arg = 0
for i in range(0, len(code), 2): for i in range(0, len(code), 2):
@ -522,6 +528,11 @@ def _unpack_opargs(code):
if op >= HAVE_ARGUMENT: if op >= HAVE_ARGUMENT:
arg = code[i+1] | extended_arg arg = code[i+1] | extended_arg
extended_arg = (arg << 8) if op == EXTENDED_ARG else 0 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
# The oparg is stored as a signed integer
# If the value exceeds its upper limit, it will overflow and wrap
# to a negative integer
if extended_arg >= _INT_OVERFLOW:
extended_arg -= 2 * _INT_OVERFLOW
else: else:
arg = None arg = None
extended_arg = 0 extended_arg = 0

View file

@ -1,14 +1,17 @@
# Minimal tests for dis module # Minimal tests for dis module
from test.support import captured_stdout, requires_debug_ranges import contextlib
from test.support.bytecode_helper import BytecodeTestCase
import unittest
import sys
import dis import dis
import io import io
import re import re
import sys
import types import types
import contextlib import unittest
from test.support import captured_stdout, requires_debug_ranges
from test.support.bytecode_helper import BytecodeTestCase
import opcode
def get_tb(): def get_tb():
def _error(): def _error():
@ -219,6 +222,22 @@ dis_bug_45757 = """\
RETURN_VALUE RETURN_VALUE
""" """
# [255, 255, 255, 252] is -4 in a 4 byte signed integer
bug46724 = bytes([
opcode.EXTENDED_ARG, 255,
opcode.EXTENDED_ARG, 255,
opcode.EXTENDED_ARG, 255,
opcode.opmap['JUMP_FORWARD'], 252,
])
dis_bug46724 = """\
>> EXTENDED_ARG 255
EXTENDED_ARG 65535
EXTENDED_ARG 16777215
JUMP_FORWARD -4 (to 0)
"""
_BIG_LINENO_FORMAT = """\ _BIG_LINENO_FORMAT = """\
1 RESUME 0 1 RESUME 0
@ -688,6 +707,10 @@ class DisTests(DisTestBase):
# Extended arg followed by NOP # Extended arg followed by NOP
self.do_disassembly_test(code_bug_45757, dis_bug_45757) self.do_disassembly_test(code_bug_45757, dis_bug_45757)
def test_bug_46724(self):
# Test that negative operargs are handled properly
self.do_disassembly_test(bug46724, dis_bug46724)
def test_big_linenos(self): def test_big_linenos(self):
def func(count): def func(count):
namespace = {} namespace = {}

View file

@ -0,0 +1 @@
Fix :mod:`dis` behavior on negative jump offsets.