mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix incorrect opline after deoptimization
Blacklisted side traces (aka JIT'ed exits) may return the previous opline after calling the original op handler. As a result, the op handler is called again by the VM. Fix this by always returning the opline returned by the original op handler. Always use zend_jit_vm_enter(jit, ref) to signal the VM that it must reload EG(current_execute_data) as it may have changed during the execution of the trace. Fixes GH-19486 Closes GH-19535
This commit is contained in:
1
NEWS
1
NEWS
@@ -54,6 +54,7 @@ PHP NEWS
|
||||
|
||||
- Opcache:
|
||||
. Fixed bug GH-19493 (JIT variable not stored before YIELD). (Arnaud)
|
||||
. Fixed bug GH-19486 (Incorrect opline after deoptimization). (Arnaud)
|
||||
|
||||
- OpenSSL:
|
||||
. Implement #81724 (openssl_cms_encrypt only allows specific ciphers).
|
||||
|
||||
@@ -17377,16 +17377,8 @@ static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const
|
||||
addr = ir_CAST_FC_FUNC(addr);
|
||||
#endif
|
||||
ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit));
|
||||
if (opline &&
|
||||
(opline->opcode == ZEND_RETURN
|
||||
|| opline->opcode == ZEND_RETURN_BY_REF
|
||||
|| opline->opcode == ZEND_GENERATOR_RETURN
|
||||
|| opline->opcode == ZEND_GENERATOR_CREATE
|
||||
|| opline->opcode == ZEND_YIELD
|
||||
|| opline->opcode == ZEND_YIELD_FROM)) {
|
||||
zend_jit_vm_enter(jit, ref);
|
||||
return 1;
|
||||
}
|
||||
zend_jit_vm_enter(jit, ref);
|
||||
return 1;
|
||||
}
|
||||
zend_jit_vm_enter(jit, jit_IP(jit));
|
||||
}
|
||||
|
||||
42
ext/opcache/tests/jit/gh19486.phpt
Normal file
42
ext/opcache/tests/jit/gh19486.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
GH-19486: incorrect opline after deoptimization
|
||||
--INI--
|
||||
opcache.jit_blacklist_root_trace=1
|
||||
opcache.jit_blacklist_side_trace=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
(new GameMap())->getLakeArea(0, 0);
|
||||
|
||||
class GameMap
|
||||
{
|
||||
public $lakeID = [];
|
||||
|
||||
public function getLakeArea(int $x, int $y): int
|
||||
{
|
||||
$this->floodFill(0, 0, 0);
|
||||
}
|
||||
|
||||
public function floodFill(int $x, int $y, int $id): void
|
||||
{
|
||||
if (($x < 0) or ($x >= 50) or ($y < 0) or ($y >= 50)) {
|
||||
return;
|
||||
}
|
||||
if (isset($this->lakeID[$y][$x]) and ($this->lakeID[$y][$x] == $id)) {
|
||||
return;
|
||||
}
|
||||
$this->lakeID[$y][$x] = $id;
|
||||
$this->floodFill($x - 1, $y, $id);
|
||||
$this->floodFill($x + 1, $y, $id);
|
||||
$this->floodFill($x, $y - 1, $id);
|
||||
$this->floodFill($x, $y + 1, $id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: GameMap::getLakeArea(): Return value must be of type int, none returned in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): GameMap->getLakeArea(0, 0)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
||||
Reference in New Issue
Block a user