From ed66bd7a3a8c91b6de45f40a5c73e5bc10774fc6 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 24 Oct 2024 21:47:55 +0200 Subject: [PATCH] Fix GH-16572: Incorrect result with reflection in low-trigger JIT When a recursive call happens with invalid arguments, the maximum valid arguments are computed and stored in `num_args`, but the RECV entry block we jump to is `call_num_args` instead. This can skip argument validation checks. Fix this by using `num_args` instead. --- ext/opcache/jit/zend_jit_ir.c | 5 ++--- ext/opcache/tests/jit/gh16572.phpt | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/jit/gh16572.phpt diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index c12298aaf3fda..892d12f2b469d 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -9887,6 +9887,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if ((!func || func->type == ZEND_USER_FUNCTION) && opline->opcode != ZEND_DO_ICALL) { bool recursive_call_through_jmp = 0; + uint32_t num_args; // JIT: EX(call) = NULL; ir_STORE(jit_CALL(rx, call), IR_NULL); @@ -9951,8 +9952,6 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (call_num_args <= func->op_array.num_args) { if (!trace || (trace->op == ZEND_JIT_TRACE_END && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) { - uint32_t num_args; - if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { if (trace) { num_args = 0; @@ -10148,7 +10147,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen ir_insn *insn; /* attempt to convert direct recursive call into loop */ - begin = jit->bb_start_ref[call_num_args]; + begin = jit->bb_start_ref[num_args]; ZEND_ASSERT(begin != IR_UNUSED); insn = &jit->ctx.ir_base[begin]; if (insn->op == IR_BEGIN) { diff --git a/ext/opcache/tests/jit/gh16572.phpt b/ext/opcache/tests/jit/gh16572.phpt new file mode 100644 index 0000000000000..b3a6850561c02 --- /dev/null +++ b/ext/opcache/tests/jit/gh16572.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-16572 (Incorrect result with reflection in low-trigger JIT) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1215 +--FILE-- +getReturnType()); +?> +--EXPECTF-- +string(19) "ReflectionNamedType" + +Fatal error: Uncaught TypeError: dumpType(): Argument #1 ($rt) must be of type ReflectionType, null given, called in %s on line %d and defined in %s:%d +Stack trace: +#0 %s(%d): dumpType(NULL) +#1 %s(%d): dumpType(Object(ReflectionNamedType)) +#2 {main} + thrown in %s on line %d