Skip to content

Commit ddbb581

Browse files
committed
Fix OSS-Fuzz #568005340: FETCH_DIM_FUNC_ARG partial conversion
The new call is compiled to FETCH_DIM_FUNC_ARG going to FETCH_OBJ_FUNC_ARG. It tries to convert the FETCH_*_FUNC_ARG to FETCH_*_R, but it skips FETCH_DIM_FUNC_ARG with the UNUSED op2, and erroneously converts the next FETCH_OBJ_FUNC_ARG to FETCH_OBJ_R, which is an unexpected state for the optimizer. Interestingly, the reference path already had the appropriate check, so we move the check upwards and do the same thing as the reference path. Closes GH-24059.
1 parent fb1bdd6 commit ddbb581

3 files changed

Lines changed: 34 additions & 1 deletion

File tree

‎NEWS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ PHP NEWS
1818
"Too few arguments" errors and crashes). (RV7PR)
1919
. Fix type inference of ADD_ARRAY_UNPACK with integer keys. (ndossche)
2020
. Fix too wide type inference for ASSIGN_DIM_OP. (ndossche)
21+
. Fix OSS-Fuzz #568005340 (FETCH_DIM_FUNC_ARG partial conversion). (ndossche)
2122

2223
- SOAP:
2324
. Fixed use of uninitialized func in do_request() on OOM bailout.

‎Zend/Optimizer/optimize_func_calls.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,13 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
240240
case ZEND_FETCH_OBJ_FUNC_ARG:
241241
case ZEND_FETCH_DIM_FUNC_ARG:
242242
if (call_stack[call - 1].func_arg_num != (uint32_t)-1
243+
&& call_stack[call - 1].last_check_func_arg_opline != NULL
243244
&& has_known_send_mode(&call_stack[call - 1], call_stack[call - 1].func_arg_num)) {
244245
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) {
245246
/* There's no TMP specialization for FETCH_OBJ_W/FETCH_DIM_W. Avoid
246247
* converting it and error at runtime in the FUNC_ARG variant. */
247248
if ((opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG)
248-
&& (opline->op1_type == IS_TMP_VAR || call_stack[call - 1].last_check_func_arg_opline == NULL)) {
249+
&& opline->op1_type == IS_TMP_VAR) {
249250
/* Don't remove the associated CHECK_FUNC_ARG opcode. */
250251
call_stack[call - 1].last_check_func_arg_opline = NULL;
251252
break;
@@ -261,6 +262,8 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
261262
/* FETCH_DIM_FUNC_ARG supports UNUSED op2, while FETCH_DIM_R does not.
262263
* Performing the replacement would create an invalid opcode. */
263264
call_stack[call - 1].try_inline = 0;
265+
/* Don't remove the associated CHECK_FUNC_ARG opcode. */
266+
call_stack[call - 1].last_check_func_arg_opline = NULL;
264267
break;
265268
}
266269

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
FETCH_DIM_FUNC_ARG with UNUSED op2 followed by other FUNC_ARG fetches must not be partially converted
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
--EXTENSIONS--
8+
opcache
9+
--FILE--
10+
<?php
11+
function test() {
12+
try {
13+
new Node($a[]->b);
14+
} catch (Error $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
try {
18+
byVal($a[][0]);
19+
} catch (Error $e) {
20+
echo $e->getMessage(), "\n";
21+
}
22+
}
23+
class Node { function __construct() {} }
24+
function byVal($x) {}
25+
test();
26+
?>
27+
--EXPECT--
28+
Cannot use [] for reading
29+
Cannot use [] for reading

0 commit comments

Comments
 (0)