Skip to content

Commit 8a896ef

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 2c911e4 commit 8a896ef

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)