Skip to content

Commit 38e1b0a

Browse files
committed
Fix phpGH-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. Closes phpGH-16575.
1 parent 757781a commit 38e1b0a

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ PHP NEWS
1212
. Fixed bug GH-16559 (UBSan abort in ext/gd/libgd/gd_interpolation.c:1007).
1313
(nielsdos)
1414

15+
- Opcache:
16+
. Fixed bug GH-16572 (Incorrect result with reflection in low-trigger JIT).
17+
(nielsdos)
18+
1519
- PDO:
1620
. Fixed bug GH-16167 (Prevent mixing PDO sub-classes with different DSN).
1721
(kocsismate)

ext/opcache/jit/zend_jit_ir.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9887,6 +9887,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
98879887
if ((!func || func->type == ZEND_USER_FUNCTION)
98889888
&& opline->opcode != ZEND_DO_ICALL) {
98899889
bool recursive_call_through_jmp = 0;
9890+
uint32_t num_args = 0;
98909891

98919892
// JIT: EX(call) = NULL;
98929893
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
99519952
if (call_num_args <= func->op_array.num_args) {
99529953
if (!trace || (trace->op == ZEND_JIT_TRACE_END
99539954
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
9954-
uint32_t num_args;
9955-
99569955
if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
99579956
if (trace) {
99589957
num_args = 0;
@@ -10148,7 +10147,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1014810147
ir_insn *insn;
1014910148

1015010149
/* attempt to convert direct recursive call into loop */
10151-
begin = jit->bb_start_ref[call_num_args];
10150+
begin = jit->bb_start_ref[num_args];
1015210151
ZEND_ASSERT(begin != IR_UNUSED);
1015310152
insn = &jit->ctx.ir_base[begin];
1015410153
if (insn->op == IR_BEGIN) {

ext/opcache/tests/jit/gh16572.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-16572 (Incorrect result with reflection in low-trigger JIT)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.jit=1215
7+
--FILE--
8+
<?php
9+
function dumpType(ReflectionType $rt) {
10+
var_dump($rt::class);
11+
dumpType(null);
12+
}
13+
function test1(): int { }
14+
dumpType((new ReflectionFunction('test1'))->getReturnType());
15+
?>
16+
--EXPECTF--
17+
string(19) "ReflectionNamedType"
18+
19+
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
20+
Stack trace:
21+
#0 %s(%d): dumpType(NULL)
22+
#1 %s(%d): dumpType(Object(ReflectionNamedType))
23+
#2 {main}
24+
thrown in %s on line %d

0 commit comments

Comments
 (0)