Skip to content

Commit d0a6e15

Browse files
miss-islingtoncocolatoblurb-it[bot]
authored
[3.15] gh-154701: prevent executor self-links in JIT cold exits (GH-155323) (#155832)
(cherry picked from commit 716cbae) Co-authored-by: Hai Zhu <haiizhu@outlook.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> * gh-154701: adapt JIT cold exit backport to 3.15 --------- Co-authored-by: Hai Zhu <haiizhu@outlook.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
1 parent b0a43d4 commit d0a6e15

6 files changed

Lines changed: 41 additions & 3 deletions

File tree

Include/internal/pycore_optimizer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ typedef struct _PyExecutorObject {
206206
PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset);
207207

208208
int _Py_ExecutorInit(_PyExecutorObject *, const _PyBloomFilter *);
209-
void _Py_ExecutorDetach(_PyExecutorObject *);
209+
PyAPI_FUNC(void) _Py_ExecutorDetach(_PyExecutorObject *);
210210
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
211211

212212
/* We use a bloomfilter with k = 6, m = 256

Include/internal/pycore_uop_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_capi/test_opt.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
import unittest
66
import gc
77
import os
8+
import subprocess
89
import types
910

1011
import _opcode
1112

1213
from test.support import (script_helper, requires_specialization,
1314
import_helper, Py_GIL_DISABLED, requires_jit_enabled,
14-
reset_code)
15+
reset_code, SHORT_TIMEOUT)
1516

1617
_testinternalcapi = import_helper.import_module("_testinternalcapi")
1718

@@ -6200,6 +6201,31 @@ def __exit__(self, e, v, t): ...
62006201
f1()
62016202
"""), PYTHON_JIT="1")
62026203

6204+
def test_for_iter_side_exit_does_not_self_link(self):
6205+
subprocess.run([sys.executable, "-c", textwrap.dedent("""
6206+
from _testinternalcapi import TIER2_THRESHOLD
6207+
6208+
def exhaust(iterator):
6209+
for _ in iterator:
6210+
pass
6211+
6212+
values = range(TIER2_THRESHOLD)
6213+
# After the initial trace, MAX_CHAIN_DEPTH side exits cause the final
6214+
# executor to be installed at FOR_ITER.
6215+
warmup_iterators = (
6216+
iter(set(values)),
6217+
iter(dict.fromkeys(values)),
6218+
iter(values),
6219+
enumerate(values),
6220+
zip(values, values),
6221+
)
6222+
for iterator in warmup_iterators:
6223+
exhaust(iterator)
6224+
6225+
# A different iterator type must not link that executor to itself.
6226+
exhaust(map(bool, values))
6227+
""")], check=True, timeout=SHORT_TIMEOUT)
6228+
62036229
def global_identity(x):
62046230
return x
62056231

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an infinite loop in JIT when a ``FOR_ITER`` side exit links an executor back to itself.

Python/bytecodes.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6308,6 +6308,10 @@ dummy_func(
63086308
if (target->op.code == ENTER_EXECUTOR) {
63096309
PyCodeObject *code = _PyFrame_GetCode(frame);
63106310
executor = code->co_executors->executors[target->op.arg];
6311+
if (executor == _PyExecutor_FromExit(exit)) {
6312+
_Py_ExecutorDetach(executor);
6313+
GOTO_TIER_ONE(target);
6314+
}
63116315
Py_INCREF(executor);
63126316
assert(tstate->jit_exit == exit);
63136317
exit->executor = executor;

Python/executor_cases.c.h

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

0 commit comments

Comments
 (0)