You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
JIT: "reg forwarding" assertion in zend_jit_def_reg (segfault in release) on masked counter loop, opcache.jit=function #24396
With opcache.jit=function, a do/while loop whose counter is masked with & 255 and tested with two ||-ed comparisons makes the JIT compiler hit an assertion in zend_jit_def_reg (debug build) or segfault (release build) while the script is loaded, even if the function is never called.
Release build: segfault (exit 139) at script load, no output.
Expected output is 2, which is what the script prints with opcache.jit=off and with opcache.jit=tracing.
Reproduced at 17b6575 (assertion in the debug build, exit 139 in the release build). $i++ without the mask, or a single comparison, does not trigger it.
This looks like the Pi/Phi register forwarding in zend_jit_gen_phi/zend_jit_def_reg (ZREG_FORWARD): the code assumes a forwarded Pi value feeds exactly one Phi, but here the loop header Phi has several Pi sources and one feeds more than one Phi. Letting zend_jit_def_reg walk all Phi uses instead of asserting a single one is not enough: a PHI operand still stays unset and ir_check reports "ops[4] missing reference (0)"; in a release build that unset operand is presumably what gets dereferenced.
I can send a patch if that helps.
The loop comes from a generated test, not from a real program.
Found with an LLM-based testing tool; I used Claude to reduce it and look for the cause.
Activity
Fix phpGH-24396: Assertion failure in zend_jit_def_reg() "reg forward…
Fix phpGH-24396: Assertion failure in zend_jit_def_reg() "reg forward…