Skip to content

Commit fdcfc0a

Browse files
committed
Fix GH-15834: Segfault with hook "simple get" cache slot and minimal JIT
The FETCH_OBJ_R VM handler has an optimization that directly enters into a hook if it is a simpler getter hook. This is not compatible with the minimal JIT because the minimal JIT will try to continue executing the opcodes after the FETCH_OBJ_R. To solve this, we check whether the opcode is still the expected one after the execution of the VM handler. If it is not, we know that we are going to execute a simple hook. In that case, exit to the VM.
1 parent 2e999ba commit fdcfc0a

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,23 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
27092709
/* We skip over the DO_FCALL, so decrement call_level ourselves. */
27102710
call_level--;
27112711
}
2712+
break;
2713+
case ZEND_FETCH_OBJ_R:
2714+
if (!zend_jit_handler(&ctx, opline,
2715+
zend_may_throw(opline, ssa_op, op_array, ssa))) {
2716+
goto jit_failure;
2717+
}
2718+
2719+
/* If a simple hook is called, exit to the VM. */
2720+
ir_ref if_hook_enter = ir_IF(jit_CMP_IP(jit, IR_EQ, opline + 1));
2721+
ir_IF_FALSE(if_hook_enter);
2722+
if (GCC_GLOBAL_REGS || zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
2723+
ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2724+
} else {
2725+
ir_RETURN(ir_CONST_I32(1)); /* ZEND_VM_ENTER */
2726+
}
2727+
ir_IF_TRUE(if_hook_enter);
2728+
27122729
break;
27132730
default:
27142731
if (!zend_jit_handler(&ctx, opline,

ext/opcache/tests/jit/gh15834.phpt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
GH-15834 (Segfault with hook "simple get" cache slot and minimal JIT)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.jit=1111
7+
--FILE--
8+
<?php
9+
class A {
10+
public $_prop = 1;
11+
public $prop {
12+
get => $this->_prop;
13+
}
14+
}
15+
16+
$a = new A;
17+
for ($i=0;$i<5;$i++) {
18+
echo $a->prop;
19+
$a->_prop++;
20+
}
21+
?>
22+
--EXPECT--
23+
12345

0 commit comments

Comments
 (0)