Skip to content

Commit 9e10f14

Browse files
authored
gh-152192: Fix JUMP_BACKWARD passing a truncated oparg to the jit tracer (GH-152382)
1 parent 189ab83 commit 9e10f14

5 files changed

Lines changed: 31 additions & 10 deletions

File tree

Lib/test/test_capi/test_opt.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import contextlib
2+
import dis
23
import itertools
34
import sys
45
import textwrap
@@ -247,6 +248,28 @@ def many_vars():
247248
self.assertTrue(any((opcode, oparg, operand) == ("_LOAD_FAST_BORROW", 259, 0)
248249
for opcode, oparg, _, operand in list(ex)))
249250

251+
def test_jump_backward_extended_arg(self):
252+
# gh-152192: a JUMP_BACKWARD that needs an EXTENDED_ARG must record its
253+
# deopt target at the EXTENDED_ARG, not the JUMP_BACKWARD.
254+
ns = {}
255+
src = ("def f(n):\n"
256+
" i = 0\n"
257+
" while i < n:\n"
258+
" i += 1\n"
259+
+ "".join(f" a = {j}\n" for j in range(140)))
260+
exec(src, ns)
261+
f = ns["f"]
262+
263+
instrs = list(dis.get_instructions(f))
264+
ext, jb = next((p, i) for p, i in zip(instrs, instrs[1:])
265+
if i.opname == "JUMP_BACKWARD" and p.opname == "EXTENDED_ARG")
266+
267+
f(TIER2_THRESHOLD + 1)
268+
ex = _opcode.get_executor(f.__code__, ext.offset)
269+
set_ips = {t for op, _, t, _ in ex if op == "_SET_IP"}
270+
self.assertIn(ext.offset // 2, set_ips)
271+
self.assertNotIn(jb.offset // 2, set_ips)
272+
250273
def test_unspecialized_unpack(self):
251274
# An example of an unspecialized opcode
252275
def testfunc(x):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a truncated ``oparg`` being passed to JIT trace initialization for a
2+
``JUMP_BACKWARD`` with an ``EXTENDED_ARG``.

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3560,8 +3560,8 @@ dummy_func(
35603560
next_instr->op.code != ENTER_EXECUTOR) {
35613561
/* Back up over EXTENDED_ARGs so executor is inserted at the correct place */
35623562
_Py_CODEUNIT *insert_exec_at = this_instr;
3563-
while (oparg > 255) {
3564-
oparg >>= 8;
3563+
// gh-152192: count with a temporary. oparg must stay intact, it's passed to the tracer below
3564+
for (int tmp = oparg; tmp > 255; tmp >>= 8) {
35653565
insert_exec_at--;
35663566
}
35673567
int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at,

Python/generated_cases.c.h

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)