summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaul Shanabrook <s.shanabrook@gmail.com>2022-02-18 09:56:23 (GMT)
committerGitHub <noreply@github.com>2022-02-18 09:56:23 (GMT)
commitc3ce7781e3afe6f2dec5eef8e87fd5a664519ae9 (patch)
tree71debab0cde3a897b78dc05cec13beeca7ae82b4
parent2923d87ca258b9d421e8147b12f0d98295ee3f8e (diff)
downloadcpython-c3ce7781e3afe6f2dec5eef8e87fd5a664519ae9.zip
cpython-c3ce7781e3afe6f2dec5eef8e87fd5a664519ae9.tar.gz
cpython-c3ce7781e3afe6f2dec5eef8e87fd5a664519ae9.tar.bz2
bpo-46724: Fix dis support for overflow args (GH-31285)
-rw-r--r--Lib/dis.py11
-rw-r--r--Lib/test/test_dis.py33
-rw-r--r--Misc/NEWS.d/next/Library/2022-02-11-20-41-17.bpo-46724.eU52_N.rst1
3 files changed, 40 insertions, 5 deletions
diff --git a/Lib/dis.py b/Lib/dis.py
index 2462a84..dc3ec16 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -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
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 4feeb8c..488b8df 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -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
index 0000000..9ac8c17
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-02-11-20-41-17.bpo-46724.eU52_N.rst
@@ -0,0 +1 @@
+Fix :mod:`dis` behavior on negative jump offsets.