diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 425c76dd01ed7c2..a2e67726e959590 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -318,6 +318,27 @@ def test_sys_api_with_existing_perf_jit_trampoline(self): """ assert_python_ok("-c", code, PYTHON_JIT="0") + @unittest.skipUnless( + "-D_Py_JIT" in (sysconfig.get_config_var("PY_CORE_CFLAGS") or "").split(), + "requires a real JIT (_Py_JIT)", + ) + def test_sys_api_perf_jit_backend_in_subinterpreter(self): + # gh-157247: a subinterpreter must not bypass the JIT/perf exclusion. + code = """if 1: + import sys + from contextlib import closing + from concurrent import interpreters + + assert sys._jit.is_enabled(), "expected the JIT to be enabled" + + with closing(interpreters.create()) as interp: + interp.exec( + "import sys; sys.activate_stack_trampoline('perf_jit')") + """ + rc, out, err = assert_python_failure("-c", code, PYTHON_JIT="1") + self.assertIn( + b"Cannot activate the perf trampoline if the JIT is active", err) + def is_unwinding_reliable_with_frame_pointers(): cflags = sysconfig.get_config_var("PY_CORE_CFLAGS") diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-10-08-21-07.gh-issue-157247.Zv4bz2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-10-08-21-07.gh-issue-157247.Zv4bz2.rst new file mode 100644 index 000000000000000..005132576a134bd --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-10-08-21-07.gh-issue-157247.Zv4bz2.rst @@ -0,0 +1,2 @@ +Fix :func:`sys.activate_stack_trampoline` allowing activation from a +subinterpreter while the JIT is enabled in the main interpreter. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 10087c1ccaac17d..03e5ac7415beb9d 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2348,7 +2348,9 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) { #ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef _Py_JIT - if (_PyInterpreterState_GET()->jit) { + // Perf state is process-wide, and only the main interpreter can enable + // the JIT. Check it even when called from a subinterpreter (gh-157247). + if (_PyInterpreterState_Main()->jit) { PyErr_SetString(PyExc_ValueError, "Cannot activate the perf trampoline if the JIT is active"); return NULL; }