[php-src] PR #24610: Fix lost register-allocated CVs on interrupt at the end of a loop trace
| From: | morrisonlevi | Date: | Fri, 23 Oct 2026 16:31:59 +0000 |
| Subject: | [php-src] PR #24610: Fix lost register-allocated CVs on interrupt at the end of a loop trace | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39772@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24610
Author: morrisonlevi
AI disclosure: I hit this bug in our CI, and I used AI to write the patch and the test. I am
certainly not a JIT expert, but I have reviewed the code to the best of my ability.
When closing a loop trace that uses the initial IP, the interrupt check either jumps to a
deoptimizing exit at the loop header or directly to jit_stub_interrupt_handler. The choice was made
with zend_jit_trace_stack_needs_deoptimization(), which only checks STACK_REG() and the slot flags.
A register-allocated variable is tracked during compilation by its IR ref only, and STACK_REG() is
still ZREG_NONE, so the stub was chosen even when a CV lived only in a register. If EG(vm_interrupt)
was raised during the iteration without a function call (e.g. by a signal handler or another
thread), the VM resumed the loop with a stale CV value.
Also check for refs that were not stored to memory, using the same criterion as the link-to-root
path.
VmInterruptComparable is backported to zend_test from 06bfe158a52 to raise the interrupt
deterministically. This is going to cause a merge-conflict when merging forward to PHP 8.5.