Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/internal/pycore_tstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ typedef struct _PyJitTracerTranslatorState {
} _PyJitTracerTranslatorState;

typedef struct _PyJitTracerState {
bool is_tracing;
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
_PyJitTracerTranslatorState translator_state;
Expand Down
45 changes: 45 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3606,6 +3606,51 @@ async def async_for_driver():
"""), PYTHON_JIT="1")
self.assertEqual(result[0].rc, 0, result)

def test_143358(self):
# https://github.com/python/cpython/issues/143358

result = script_helper.run_python_until_end('-c', textwrap.dedent(f"""
def f1():

class EvilIterator:

def __init__(self):
self._items = [1, 2]
self._index = 1

def __iter__(self):
return self

def __next__(self):
if not len(self._items) % 13:
self._items.clear()

for i_loop_9279 in range(10):
self._items.extend([1, "", None])

if not len(self._items) % 11:
return 'unexpected_type_from_iterator'

if self._index >= len(self._items):
raise StopIteration

item = self._items[self._index]
self._index += 1
return item

evil_iter = EvilIterator()

large_num = 2**31
for _ in range(400):
try:
_ = [x + y for x in evil_iter for y in evil_iter if evil_iter._items.append(x) or large_num]
except TypeError:
pass

f1()
"""), PYTHON_JIT="1", PYTHON_JIT_JUMP_BACKWARD_INITIAL_VALUE="64")
self.assertEqual(result[0].rc, 0, result)

def global_identity(x):
return x

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Protect the JIT against recursive tracing.
10 changes: 10 additions & 0 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -5607,6 +5607,16 @@ dummy_func(
#else
assert(_PyErr_Occurred(tstate));
#endif
#if _Py_TIER2
if (IS_JIT_TRACING()) {
LEAVE_TRACING();
int res = stop_tracing_and_jit(tstate, frame);
(void)res;
// We shouldn't ven have compiled in the first place.
assert(res == 0);
}
#endif


/* Log traceback info. */
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
Expand Down
10 changes: 10 additions & 0 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Python/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,11 +1030,11 @@ _PyJit_TryInitializeTracing(
// Don't error, just go to next instruction.
return 0;
}
_tstate->jit_tracer_state->is_tracing = false;
}
_PyJitTracerState *tracer = _tstate->jit_tracer_state;
// A recursive trace.
// Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces.
if (tracer->prev_state.code_curr_size > CODE_SIZE_EMPTY) {
if (tracer->is_tracing) {
return 0;
}
if (oparg > 0xFFFF) {
Expand Down Expand Up @@ -1086,6 +1086,7 @@ _PyJit_TryInitializeTracing(
close_loop_instr[1].counter = trigger_backoff_counter();
}
_Py_BloomFilter_Init(&tracer->prev_state.dependencies);
tracer->is_tracing = true;
return 1;
}

Expand All @@ -1100,6 +1101,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate)
Py_CLEAR(tracer->prev_state.instr_code);
tracer->prev_state.code_curr_size = CODE_SIZE_EMPTY;
tracer->prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2 - 1;
tracer->is_tracing = false;
}

void
Expand Down
Loading