mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
When the JIT defers the IS_UNDEF check for FETCH_OBJ_R to the result type guard, the deoptimization escape path dispatches to opline->handler via the trace_escape stub. If opline->handler has been overwritten with JIT code (e.g. a function entry trace), this creates an infinite loop. Fix by dispatching to the original VM handler (orig_handler from the trace extension) instead of going through the trace_escape stub. This avoids the extra IS_UNDEF guard on every property read while correctly handling the rare IS_UNDEF case during deoptimization. Also set current_op_array in zend_jit_trace_exit_to_vm so that the blacklisted exit deoptimizer can resolve orig_handler, covering the case where side trace compilation is exhausted. Closes GH-21368.
37 lines
662 B
PHP
37 lines
662 B
PHP
--TEST--
|
|
GH-21267 (JIT infinite loop on FETCH_OBJ_R with IS_UNDEF via blacklisted trace exit)
|
|
--INI--
|
|
opcache.enable=1
|
|
opcache.enable_cli=1
|
|
opcache.jit=tracing
|
|
opcache.jit_buffer_size=64M
|
|
opcache.jit_hot_loop=0
|
|
opcache.jit_hot_func=2
|
|
opcache.jit_hot_return=0
|
|
opcache.jit_hot_side_exit=1
|
|
opcache.jit_max_side_traces=0
|
|
--FILE--
|
|
<?php
|
|
class C {
|
|
public $x = true;
|
|
public function __get($name) { return null; }
|
|
public function getX() { return $this->x; }
|
|
}
|
|
|
|
$o1 = new C;
|
|
$o2 = new C;
|
|
$o2->x = false;
|
|
$o3 = new C;
|
|
unset($o3->x);
|
|
$a = [$o1, $o2, $o3];
|
|
|
|
for ($i = 0; $i < 8; $i++) {
|
|
$m = $a[$i % 3];
|
|
$m->getX();
|
|
$m->getX();
|
|
}
|
|
?>
|
|
OK
|
|
--EXPECT--
|
|
OK
|