Skip to content

Commit 0bd3a6b

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Fix support for TAILCALL VM Fix GH-21267: JIT infinite loop on FETCH_OBJ_R with IS_UNDEF property (#21368)
2 parents 25f62cf + 00ff93d commit 0bd3a6b

4 files changed

Lines changed: 87 additions & 3 deletions

File tree

ext/opcache/jit/zend_jit_ir.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7949,7 +7949,7 @@ static int zend_jit_defined(zend_jit_ctx *jit, const zend_op *opline, uint8_t sm
79497949
return 1;
79507950
}
79517951

7952-
static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, int8_t reg)
7952+
static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, const zend_op_array *op_array, int8_t reg)
79537953
{
79547954
zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
79557955
ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
@@ -7972,7 +7972,20 @@ static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags,
79727972
}
79737973

79747974
jit_LOAD_IP_ADDR(jit, opline - 1);
7975-
ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
7975+
7976+
/* We can't use trace_escape() because opcode handler may be overridden by JIT */
7977+
zend_jit_op_array_trace_extension *jit_extension =
7978+
(zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7979+
size_t offset = jit_extension->offset;
7980+
ir_ref ref = ir_CONST_ADDR(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler);
7981+
if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
7982+
ir_TAILCALL(IR_OPCODE_HANDLER_RET, ref);
7983+
} else {
7984+
#if defined(IR_TARGET_X86)
7985+
ref = ir_CAST_FC_FUNC(ref);
7986+
#endif
7987+
ir_TAILCALL_2(IR_ADDR, ref, jit_FP(jit), jit_IP(jit));
7988+
}
79767989

79777990
ir_IF_TRUE(if_def);
79787991

ext/opcache/jit/zend_jit_trace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3649,7 +3649,7 @@ static int zend_jit_trace_deoptimization(
36493649

36503650
ZEND_ASSERT(STACK_FLAGS(parent_stack, check2) == ZREG_ZVAL_COPY);
36513651
ZEND_ASSERT(reg != ZREG_NONE);
3652-
if (!zend_jit_escape_if_undef(jit, check2, flags, opline, reg)) {
3652+
if (!zend_jit_escape_if_undef(jit, check2, flags, opline, exit_info->op_array, reg)) {
36533653
return 0;
36543654
}
36553655
if (!zend_jit_restore_zval(jit, EX_NUM_TO_VAR(check2), reg)) {

ext/opcache/tests/jit/gh21267.phpt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
GH-21267 (JIT infinite loop on FETCH_OBJ_R with IS_UNDEF property in polymorphic context)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.jit=tracing
7+
opcache.jit_buffer_size=64M
8+
opcache.jit_hot_loop=0
9+
opcache.jit_hot_func=2
10+
opcache.jit_hot_return=0
11+
opcache.jit_hot_side_exit=1
12+
--FILE--
13+
<?php
14+
class C {
15+
public $x = true;
16+
public function __get($name) { return null; }
17+
public function getX() { return $this->x; }
18+
}
19+
20+
$o1 = new C;
21+
$o2 = new C;
22+
$o2->x = false;
23+
$o3 = new C;
24+
unset($o3->x);
25+
$a = [$o1, $o2, $o3];
26+
27+
for ($i = 0; $i < 8; $i++) {
28+
$m = $a[$i % 3];
29+
$m->getX();
30+
$m->getX();
31+
}
32+
?>
33+
OK
34+
--EXPECT--
35+
OK
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
GH-21267 (JIT infinite loop on FETCH_OBJ_R with IS_UNDEF via blacklisted trace exit)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.jit=tracing
7+
opcache.jit_buffer_size=64M
8+
opcache.jit_hot_loop=0
9+
opcache.jit_hot_func=2
10+
opcache.jit_hot_return=0
11+
opcache.jit_hot_side_exit=1
12+
opcache.jit_max_side_traces=0
13+
--FILE--
14+
<?php
15+
class C {
16+
public $x = true;
17+
public function __get($name) { return null; }
18+
public function getX() { return $this->x; }
19+
}
20+
21+
$o1 = new C;
22+
$o2 = new C;
23+
$o2->x = false;
24+
$o3 = new C;
25+
unset($o3->x);
26+
$a = [$o1, $o2, $o3];
27+
28+
for ($i = 0; $i < 8; $i++) {
29+
$m = $a[$i % 3];
30+
$m->getX();
31+
$m->getX();
32+
}
33+
?>
34+
OK
35+
--EXPECT--
36+
OK

0 commit comments

Comments
 (0)