Skip to content

Function JIT (8.4+): wrong result after interrupts are handled in a loop #23983

Description

@frodeborli

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:

bool(false)

But I expected this output instead:

bool(true)

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

Activity

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