]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46724: Fix dis support for overflow args (GH-31285)
authorSaul Shanabrook <s.shanabrook@gmail.com>
Fri, 18 Feb 2022 09:56:23 +0000 (04:56 -0500)
committerGitHub <noreply@github.com>
Fri, 18 Feb 2022 09:56:23 +0000 (09:56 +0000)
Lib/dis.py
Lib/test/test_dis.py
Misc/NEWS.d/next/Library/2022-02-11-20-41-17.bpo-46724.eU52_N.rst [new file with mode: 0644]

index 2462a8434e89502938a0d1446649e1be8cc67e91..dc3ec169abecf0178c8d811be90da6be6e9e9454 100644 (file)
@@ -515,6 +515,12 @@ def _disassemble_str(source, **kwargs):
 
 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):
@@ -522,6 +528,11 @@ def _unpack_opargs(code):
         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
index 4feeb8c5be8a2502519a091b2d647601a7c7a156..488b8dffdedbf2d056dbcae74367f6685a3d9bdf 100644 (file)
@@ -1,14 +1,17 @@
 # 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():
@@ -219,6 +222,22 @@ dis_bug_45757 = """\
        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
 
@@ -688,6 +707,10 @@ class DisTests(DisTestBase):
         # 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 = {}
diff --git a/Misc/NEWS.d/next/Library/2022-02-11-20-41-17.bpo-46724.eU52_N.rst b/Misc/NEWS.d/next/Library/2022-02-11-20-41-17.bpo-46724.eU52_N.rst
new file mode 100644 (file)
index 0000000..9ac8c17
--- /dev/null
@@ -0,0 +1 @@
+Fix :mod:`dis` behavior on negative jump offsets.