Skip to content

JIT: "reg forwarding" assertion in zend_jit_def_reg (segfault in release) on masked counter loop, opcache.jit=function #24396

Open

Description

@waroad

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.

<?php
function f() { $i = 0; do { $i = ($i + 1) & 255; } while ($i < 2 || $i > 200); return $i; }
echo f(), "\n";
php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=64M -d opcache.jit=function reduced.php

Debug build (assertions enabled):

php: ext/opcache/jit/zend_jit_ir.c:1357: zend_jit_def_reg: Assertion `!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding"' failed.

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

  1. self-assigned this
    on Oct 18, 2026
  2. added 2 commits that reference this issue on Oct 18, 2026
    680696f
    79a67d4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions