https://github.com/python/cpython/commit/9e10f14b925562a0292c920608e24f89ee5f187e
commit: 9e10f14b925562a0292c920608e24f89ee5f187e
branch: main
author: Timofei <[email protected]>
committer: markshannon <[email protected]>
date: 2026-06-30T10:46:59+01:00
summary:
gh-152192: Fix JUMP_BACKWARD passing a truncated oparg to the jit tracer
(GH-152382)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst
M Lib/test/test_capi/test_opt.py
M Modules/_testinternalcapi/test_cases.c.h
M Python/bytecodes.c
M Python/generated_cases.c.h
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 2248920c266aef5..25b2c393e6773de 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1,4 +1,5 @@
import contextlib
+import dis
import itertools
import sys
import textwrap
@@ -247,6 +248,28 @@ def many_vars():
self.assertTrue(any((opcode, oparg, operand) == ("_LOAD_FAST_BORROW",
259, 0)
for opcode, oparg, _, operand in list(ex)))
+ def test_jump_backward_extended_arg(self):
+ # gh-152192: a JUMP_BACKWARD that needs an EXTENDED_ARG must record its
+ # deopt target at the EXTENDED_ARG, not the JUMP_BACKWARD.
+ ns = {}
+ src = ("def f(n):\n"
+ " i = 0\n"
+ " while i < n:\n"
+ " i += 1\n"
+ + "".join(f" a = {j}\n" for j in range(140)))
+ exec(src, ns)
+ f = ns["f"]
+
+ instrs = list(dis.get_instructions(f))
+ ext, jb = next((p, i) for p, i in zip(instrs, instrs[1:])
+ if i.opname == "JUMP_BACKWARD" and p.opname ==
"EXTENDED_ARG")
+
+ f(TIER2_THRESHOLD + 1)
+ ex = _opcode.get_executor(f.__code__, ext.offset)
+ set_ips = {t for op, _, t, _ in ex if op == "_SET_IP"}
+ self.assertIn(ext.offset // 2, set_ips)
+ self.assertNotIn(jb.offset // 2, set_ips)
+
def test_unspecialized_unpack(self):
# An example of an unspecialized opcode
def testfunc(x):
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst
new file mode 100644
index 000000000000000..153cbeb317a2452
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-06-26-22-38-21.gh-issue-152192.lX2jIM.rst
@@ -0,0 +1,2 @@
+Fix a truncated ``oparg`` being passed to JIT trace initialization for a
+``JUMP_BACKWARD`` with an ``EXTENDED_ARG``.
diff --git a/Modules/_testinternalcapi/test_cases.c.h
b/Modules/_testinternalcapi/test_cases.c.h
index fdc077c9549a144..51234e8749de261 100644
--- a/Modules/_testinternalcapi/test_cases.c.h
+++ b/Modules/_testinternalcapi/test_cases.c.h
@@ -8582,8 +8582,7 @@
(this_instr->op.code == JUMP_BACKWARD_JIT ||
is_resume)) &&
next_instr->op.code != ENTER_EXECUTOR) {
_Py_CODEUNIT *insert_exec_at = this_instr;
- while (oparg > 255) {
- oparg >>= 8;
+ for (int tmp = oparg; tmp > 255; tmp >>= 8) {
insert_exec_at--;
}
int succ = _PyJit_TryInitializeTracing(tstate, frame,
this_instr, insert_exec_at,
@@ -11575,8 +11574,7 @@
(this_instr->op.code == JUMP_BACKWARD_JIT ||
is_resume)) &&
next_instr->op.code != ENTER_EXECUTOR) {
_Py_CODEUNIT *insert_exec_at = this_instr;
- while (oparg > 255) {
- oparg >>= 8;
+ for (int tmp = oparg; tmp > 255; tmp >>= 8) {
insert_exec_at--;
}
int succ = _PyJit_TryInitializeTracing(tstate, frame,
this_instr, insert_exec_at,
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 31596e0bc7a31d2..7fb48516e2eae73 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -3560,8 +3560,8 @@ dummy_func(
next_instr->op.code != ENTER_EXECUTOR) {
/* Back up over EXTENDED_ARGs so executor is inserted at the
correct place */
_Py_CODEUNIT *insert_exec_at = this_instr;
- while (oparg > 255) {
- oparg >>= 8;
+ // gh-152192: count with a temporary. oparg must stay intact,
it's passed to the tracer below
+ for (int tmp = oparg; tmp > 255; tmp >>= 8) {
insert_exec_at--;
}
int succ = _PyJit_TryInitializeTracing(tstate, frame,
this_instr, insert_exec_at,
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 0da86abed67f63b..4b472aecc5fc3aa 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -8581,8 +8581,7 @@
(this_instr->op.code == JUMP_BACKWARD_JIT ||
is_resume)) &&
next_instr->op.code != ENTER_EXECUTOR) {
_Py_CODEUNIT *insert_exec_at = this_instr;
- while (oparg > 255) {
- oparg >>= 8;
+ for (int tmp = oparg; tmp > 255; tmp >>= 8) {
insert_exec_at--;
}
int succ = _PyJit_TryInitializeTracing(tstate, frame,
this_instr, insert_exec_at,
@@ -11572,8 +11571,7 @@
(this_instr->op.code == JUMP_BACKWARD_JIT ||
is_resume)) &&
next_instr->op.code != ENTER_EXECUTOR) {
_Py_CODEUNIT *insert_exec_at = this_instr;
- while (oparg > 255) {
- oparg >>= 8;
+ for (int tmp = oparg; tmp > 255; tmp >>= 8) {
insert_exec_at--;
}
int succ = _PyJit_TryInitializeTracing(tstate, frame,
this_instr, insert_exec_at,
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]