Skip to content

Commit 37c6db6

Browse files
authored
gh-91869: Fix tracing of specialized instructions with extended args (GH-91945)
1 parent 407c3af commit 37c6db6

File tree

9 files changed

+145
-88
lines changed

9 files changed

+145
-88
lines changed

Include/internal/pycore_opcode.h

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

Include/opcode.h

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

Lib/importlib/_bootstrap_external.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ def _write_atomic(path, data, mode=0o666):
416416
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
417417
# in PC/launcher.c must also be updated.
418418

419-
MAGIC_NUMBER = (3493).to_bytes(2, 'little') + b'\r\n'
419+
MAGIC_NUMBER = (3494).to_bytes(2, 'little') + b'\r\n'
420420

421421
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
422422

Lib/opcode.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ def jabs_op(name, op, entries=0):
264264
"COMPARE_OP_INT_JUMP",
265265
"COMPARE_OP_STR_JUMP",
266266
],
267+
"EXTENDED_ARG": [
268+
"EXTENDED_ARG_QUICK",
269+
],
267270
"JUMP_BACKWARD": [
268271
"JUMP_BACKWARD_QUICK",
269272
],

Lib/test/test_sys_settrace.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,5 +2432,47 @@ def gen():
24322432
output.append(5)
24332433

24342434

2435+
class TestExtendedArgs(unittest.TestCase):
2436+
2437+
def setUp(self):
2438+
self.addCleanup(sys.settrace, sys.gettrace())
2439+
sys.settrace(None)
2440+
2441+
def count_traces(self, func):
2442+
# warmup
2443+
for _ in range(20):
2444+
func()
2445+
2446+
counts = {"call": 0, "line": 0, "return": 0}
2447+
def trace(frame, event, arg):
2448+
counts[event] += 1
2449+
return trace
2450+
2451+
sys.settrace(trace)
2452+
func()
2453+
sys.settrace(None)
2454+
2455+
return counts
2456+
2457+
def test_trace_unpack_long_sequence(self):
2458+
ns = {}
2459+
code = "def f():\n (" + "y,\n "*300 + ") = range(300)"
2460+
exec(code, ns)
2461+
counts = self.count_traces(ns["f"])
2462+
self.assertEqual(counts, {'call': 1, 'line': 301, 'return': 1})
2463+
2464+
def test_trace_lots_of_globals(self):
2465+
code = """if 1:
2466+
def f():
2467+
return (
2468+
{}
2469+
)
2470+
""".format("\n+\n".join(f"var{i}\n" for i in range(1000)))
2471+
ns = {f"var{i}": i for i in range(1000)}
2472+
exec(code, ns)
2473+
counts = self.count_traces(ns["f"])
2474+
self.assertEqual(counts, {'call': 1, 'line': 2000, 'return': 1})
2475+
2476+
24352477
if __name__ == "__main__":
24362478
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an issue where specialized opcodes with extended arguments could produce incorrect tracing output or lead to assertion failures.

Python/ceval.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5624,6 +5624,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
56245624
}
56255625

56265626
TARGET(EXTENDED_ARG) {
5627+
assert(oparg);
5628+
oparg <<= 8;
5629+
oparg |= _Py_OPARG(*next_instr);
5630+
opcode = _PyOpcode_Deopt[_Py_OPCODE(*next_instr)];
5631+
PRE_DISPATCH_GOTO();
5632+
DISPATCH_GOTO();
5633+
}
5634+
5635+
TARGET(EXTENDED_ARG_QUICK) {
56275636
assert(oparg);
56285637
oparg <<= 8;
56295638
oparg |= _Py_OPARG(*next_instr);

Python/compile.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,13 @@ write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen)
211211
int caches = _PyOpcode_Caches[opcode];
212212
switch (ilen - caches) {
213213
case 4:
214-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 24) & 0xFF);
214+
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG_QUICK, (oparg >> 24) & 0xFF);
215215
/* fall through */
216216
case 3:
217-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 16) & 0xFF);
217+
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG_QUICK, (oparg >> 16) & 0xFF);
218218
/* fall through */
219219
case 2:
220-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 8) & 0xFF);
220+
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG_QUICK, (oparg >> 8) & 0xFF);
221221
/* fall through */
222222
case 1:
223223
*codestr++ = _Py_MAKECODEUNIT(opcode, oparg & 0xFF);
@@ -8254,6 +8254,7 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap)
82548254
struct instr *inst = &b->b_instr[i];
82558255
// This is called before extended args are generated.
82568256
assert(inst->i_opcode != EXTENDED_ARG);
8257+
assert(inst->i_opcode != EXTENDED_ARG_QUICK);
82578258
int oldoffset = inst->i_oparg;
82588259
switch(inst->i_opcode) {
82598260
case MAKE_CELL:

0 commit comments

Comments
 (0)