Repository navigation
Fix GH-17990: Tracing JIT uses the SSA of a dead process - #25399
kamil-tekiela wants to merge 1 commit into
Conversation
The tracing JIT stores the SSA of each function of a trace in the func_info of the op_array, which is in shared memory. The SSA itself is in the arena of the compiling process, and zend_jit_trace() resets the func_info when the compilation ends. A process that dies during the compilation leaves the func_info behind. The next process that compiles a trace through the same function finds a non-zero ssa->cfg.blocks_count and reads the pointers of the dead process. Reuse an SSA only if the current compilation built it, and block interruptions during the compilation, as the rest of opcache does while it changes shared memory. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
iliaal
left a comment
There was a problem hiding this comment.
LGTM. The zend_jit_trace_has_ssa() check is what fixes this: on its own it makes both your SIGKILL test and a SIGTERM variant pass, while the interruption blocking on its own only fixes SIGTERM. It's worth saying that in the commit message.
Not for this PR, but both compile functions install the new code (opline->handler = handler, zend_jit_link_side_trace()) before ZEND_JIT_TRACE_NUM++, so a SIGKILL between those stores leaves live code pointing at a trace slot the next compilation reuses. The window is only a few stores.
| zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS]; | ||
| bool do_bailout = 0; | ||
|
|
||
| /* Don't let a signal kill the process while func_info in SHM refers to our arena */ |
There was a problem hiding this comment.
This only defers the signals zend_signal handles (SIGTERM, SIGINT, SIGHUP...). SIGKILL, a segfault or the OOM killer still end the process here, and that is the case your test covers. Maybe /* Defer signals while func_info in SHM refers to our arena */?
| zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS]; | ||
| bool do_bailout = 0; | ||
|
|
||
| /* Don't let a signal kill the process while func_info in SHM refers to our arena */ |
The tracing JIT stores the SSA of each function of a trace in the func_info of the op_array, which is in shared memory. The SSA itself is in the arena of the compiling process, and zend_jit_trace() resets the func_info when the compilation ends.
A process that dies during the compilation leaves the func_info behind. The next process that compiles a trace through the same function finds a non-zero ssa->cfg.blocks_count and reads the pointers of the dead process.
Reuse an SSA only if the current compilation built it, and block interruptions during the compilation, as the rest of opcache does while it changes shared memory.
Fixes #17990 Can you check if this fixes the problem? @YuanchengJiang