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):
extended_arg = 0
for i in range(0, len(code), 2):
if op >= HAVE_ARGUMENT:
arg = code[i+1] | extended_arg
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:
arg = None
extended_arg = 0
# Minimal tests for dis module
-from test.support import captured_stdout, requires_debug_ranges
-from test.support.bytecode_helper import BytecodeTestCase
-import unittest
-import sys
+import contextlib
import dis
import io
import re
+import sys
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 _error():
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 = """\
1 RESUME 0
# Extended arg followed by NOP
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 func(count):
namespace = {}