Description
With the function JIT (opcache.jit=function) on PHP 8.4 and later, the function below returns a wrong result when interrupts (EG(vm_interrupt)) are handled while its loops run. Here the interrupt comes from pcntl_async_signals(); any zend_interrupt_function user triggers it the same way.
<?php
$n = 0;
pcntl_async_signals(true);
pcntl_signal(SIGUSR1, function () use (&$n) { $n++; });
$pid = getmypid();
$p = proc_open(['sh', '-c', "while kill -USR1 $pid 2>/dev/null; do sleep 0.01; done"], [], $pipes);
function f(&$n) {
$x = 7;
for ($i = 1; $n < 20; $i++) {
$x = ($x * 31 + $i) & 0xffffff;
}
$y = 7;
for ($j = 1; $j < $i; $j++) {
$y = ($y * 31 + $j) & 0xffffff;
}
return $x === $y;
}
var_dump(f($n));
proc_terminate($p);
php -d opcache.enable_cli=1 -d opcache.jit=function -d opcache.jit_buffer_size=64M test.php
Resulted in this output:
But I expected this output instead:
It fails on every run with 8.4.16, 8.5.11 and master; 8.2.30 and 8.3.35 (the pre-IR JIT) print bool(true), as do 8.4+ with opcache.jit=tracing or without the JIT. Small changes make it pass: $e = $x === $y; return $e;, returning [$x === $y, $x, $y] (which shows $x and $y equal), or a var_dump() inside f(). So it looks like a register-allocated value not being kept across the interrupt handler call.
PHP Version
PHP 8.5.11 (cli) (NTS), also 8.4.16 and master (8.7.0-dev)
Operating System
Ubuntu 24.04, x86_64
Description
With the function JIT (
opcache.jit=function) on PHP 8.4 and later, the function below returns a wrong result when interrupts (EG(vm_interrupt)) are handled while its loops run. Here the interrupt comes frompcntl_async_signals(); anyzend_interrupt_functionuser triggers it the same way.Resulted in this output:
But I expected this output instead:
It fails on every run with 8.4.16, 8.5.11 and master; 8.2.30 and 8.3.35 (the pre-IR JIT) print
bool(true), as do 8.4+ withopcache.jit=tracingor without the JIT. Small changes make it pass:$e = $x === $y; return $e;, returning[$x === $y, $x, $y](which shows$xand$yequal), or avar_dump()insidef(). So it looks like a register-allocated value not being kept across the interrupt handler call.PHP Version
Operating System
Ubuntu 24.04, x86_64