diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index a958a2453c4e..72b66e2f3246 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2731,6 +2731,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op call_level--; } break; + /* FETCH_OBJ_FUNC_ARG may dispatch into the FETCH_OBJ_R handler (if sent by value). */ + case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_R: if (!zend_jit_handler(&ctx, opline, zend_may_throw(opline, ssa_op, op_array, ssa))) { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 41136bcd8051..dbb4ea1fa5b5 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -333,6 +333,8 @@ static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op // TODO: recompilation may change target ??? return 0; #endif + /* FETCH_OBJ_FUNC_ARG may dispatch into the FETCH_OBJ_R handler (if sent by value). */ + case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_R: if (opline->op2_type == IS_CONST) { const zend_class_entry *ce = opline->op1_type == IS_UNUSED ? op_array->scope : NULL; diff --git a/ext/opcache/tests/jit/gh24398.phpt b/ext/opcache/tests/jit/gh24398.phpt new file mode 100644 index 000000000000..948ac8f1b261 --- /dev/null +++ b/ext/opcache/tests/jit/gh24398.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-24398: Function JIT level 1 crash on FETCH_OBJ_FUNC_ARG of a hooked property +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=64M +opcache.jit=1201 +--EXTENSIONS-- +opcache +--FILE-- + 5; + } +} + +if (true) { + function g($x) { + return $x; + } +} + +function f($o) { + return g($o->prop); +} + +$c = new C(); +var_dump(f($c)); +var_dump(f($c)); + +?> +--EXPECT-- +int(5) +int(5) diff --git a/ext/opcache/tests/jit/gh24398_002.phpt b/ext/opcache/tests/jit/gh24398_002.phpt new file mode 100644 index 000000000000..b8b0c0481c77 --- /dev/null +++ b/ext/opcache/tests/jit/gh24398_002.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-24398 (tracing): FETCH_OBJ_FUNC_ARG of a hooked property with unknown send mode +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit_buffer_size=64M +opcache.jit=tracing +opcache.jit_hot_loop=1 +--EXTENSIONS-- +opcache +--FILE-- + 5; + } +} + +if (true) { + function g($x) { + return $x; + } +} + +function f($o) { + // The named argument leaves the send mode unknown to the tracing JIT, + // so FETCH_OBJ_FUNC_ARG is executed by the VM handler. + return g(x: $o->prop); +} + +$sum = 0; +foreach ([new A, new A, new A, new B, new B, new B] as $o) { + $sum += f($o); +} +var_dump($sum); + +?> +--EXPECT-- +int(30)