From 622f60ffc98ad9fd702c700eeb6fbda225d468ed Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Sun, 19 Jul 2026 14:14:11 +0000 Subject: [PATCH 1/7] gh-154014: Initialize cold executor vm_data fields --- Python/optimizer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index c9f6ebdb62f07b2..34db61c2a31f524 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1788,7 +1788,6 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s } return 0; } - static _PyExecutorObject * make_cold_executor(uint16_t opcode) { @@ -1796,10 +1795,17 @@ make_cold_executor(uint16_t opcode) if (cold == NULL) { Py_FatalError("Cannot allocate core JIT code"); } + ((_PyUOpInstruction *)cold->trace)->opcode = opcode; + + // Cold executors bypass _Py_ExecutorInit(). + cold->vm_data.valid = true; + cold->vm_data.pending_deletion = 0; + // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. cold->vm_data.cold = false; + #ifdef _Py_JIT cold->jit_code = NULL; cold->jit_size = 0; @@ -1808,6 +1814,7 @@ make_cold_executor(uint16_t opcode) Py_FatalError("Cannot allocate core JIT code"); } #endif + _Py_SetImmortal((PyObject *)cold); return cold; } From 58b9f510b3a7e0bba8e0c594900b3303ee903e4d Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Sun, 19 Jul 2026 16:11:16 +0000 Subject: [PATCH 2/7] gh-154014: Remove stray formatting changes --- Python/optimizer.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index 34db61c2a31f524..23d0f5b875a67c4 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1788,6 +1788,7 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s } return 0; } + static _PyExecutorObject * make_cold_executor(uint16_t opcode) { @@ -1795,9 +1796,7 @@ make_cold_executor(uint16_t opcode) if (cold == NULL) { Py_FatalError("Cannot allocate core JIT code"); } - ((_PyUOpInstruction *)cold->trace)->opcode = opcode; - // Cold executors bypass _Py_ExecutorInit(). cold->vm_data.valid = true; cold->vm_data.pending_deletion = 0; @@ -1805,7 +1804,6 @@ make_cold_executor(uint16_t opcode) // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. cold->vm_data.cold = false; - #ifdef _Py_JIT cold->jit_code = NULL; cold->jit_size = 0; @@ -1814,7 +1812,6 @@ make_cold_executor(uint16_t opcode) Py_FatalError("Cannot allocate core JIT code"); } #endif - _Py_SetImmortal((PyObject *)cold); return cold; } From 4ce06d1dccb7cf244b40935ba98b0b1ccf4d20c2 Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Sun, 19 Jul 2026 16:18:54 +0000 Subject: [PATCH 3/7] gh-154014: Add NEWS entry --- .../2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst new file mode 100644 index 000000000000000..6bdcf83725168a2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-16-18-25.gh-issue-154014.CJsjVL.rst @@ -0,0 +1,2 @@ +Fix a JIT assertion during interpreter shutdown by initializing ``vm_data`` +fields for cold executors that bypass ``_Py_ExecutorInit()``. From 0ebcf8cec8deb224d4e4c22a256262fa67af6d0b Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Sun, 19 Jul 2026 16:27:57 +0000 Subject: [PATCH 4/7] gh-154014: Add regression test --- Lib/test/test_capi/test_opt.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 25b2c393e6773de..5806216d46e7eb6 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5127,6 +5127,16 @@ def f(): f" {executor} at offset {idx} rather" f" than expected _EXIT_TRACE") + def test_jit_shutdown_after_cold_executor_creation(self): + script_helper.assert_python_ok("-c", textwrap.dedent(f""" + def f(): + for x in range({TIER2_THRESHOLD + 3}): + for y in range({TIER2_THRESHOLD + 3}): + z = x + y + + f() + """), PYTHON_JIT="1") + def test_enter_executor_valid_op_arg(self): script_helper.assert_python_ok("-c", textwrap.dedent(""" import sys From bcd78aa53e63f8588b9bfd2bef0bd24813190707 Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Mon, 20 Jul 2026 12:24:19 +0000 Subject: [PATCH 5/7] gh-154014: Initialize cold executor vm_data.code --- Python/optimizer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/optimizer.c b/Python/optimizer.c index 23d0f5b875a67c4..c1fe2b108d601ad 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1800,6 +1800,7 @@ make_cold_executor(uint16_t opcode) // Cold executors bypass _Py_ExecutorInit(). cold->vm_data.valid = true; cold->vm_data.pending_deletion = 0; + cold->vm_data.code = NULL; // This is initialized to false so we can prevent the executor // from being immediately detected as cold and invalidated. From 1f0ea1f2df5fad4f336f3f01b54223d6e7db571c Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Mon, 20 Jul 2026 12:46:06 +0000 Subject: [PATCH 6/7] gh-154014: Free unregistered cold executors directly --- Python/optimizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index c1fe2b108d601ad..dfd3c0b10ff15d1 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1809,7 +1809,7 @@ make_cold_executor(uint16_t opcode) cold->jit_code = NULL; cold->jit_size = 0; if (_PyJIT_Compile(cold, cold->trace, 1)) { - Py_DECREF(cold); + PyExecutor_Free(cold); Py_FatalError("Cannot allocate core JIT code"); } #endif From d513fdc80cfd3482c235f9d3cc7db3d3cf8dc067 Mon Sep 17 00:00:00 2001 From: Bhuvansh Kataria Date: Mon, 20 Jul 2026 12:51:50 +0000 Subject: [PATCH 7/7] gh-154014: Use internal executor free helper --- Python/optimizer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index dfd3c0b10ff15d1..e05adb344c8d06d 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1809,7 +1809,7 @@ make_cold_executor(uint16_t opcode) cold->jit_code = NULL; cold->jit_size = 0; if (_PyJIT_Compile(cold, cold->trace, 1)) { - PyExecutor_Free(cold); + _PyExecutor_Free(cold); Py_FatalError("Cannot allocate core JIT code"); } #endif