Skip to content

Commit fd879e6

Browse files
committed
JIT: Fix array clobbering by user error handler
Gixes oss-fuzz #43055
1 parent cb3d858 commit fd879e6

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim,
456456
zend_ulong hval;
457457
zend_string *offset_key;
458458
zval *retval;
459+
zend_execute_data *execute_data;
460+
const zend_op *opline;
459461

460462
if (Z_TYPE_P(dim) == IS_REFERENCE) {
461463
dim = Z_REFVAL_P(dim);
@@ -469,7 +471,31 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim,
469471
offset_key = Z_STR_P(dim);
470472
goto str_index;
471473
case IS_UNDEF:
474+
/* The array may be destroyed while throwing the notice.
475+
* Temporarily increase the refcount to detect this situation. */
476+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
477+
GC_ADDREF(ht);
478+
}
479+
execute_data = EG(current_execute_data);
480+
opline = EX(opline);
472481
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
482+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
483+
zend_array_destroy(ht);
484+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
485+
if (EG(exception)) {
486+
ZVAL_UNDEF(EX_VAR(opline->result.var));
487+
} else {
488+
ZVAL_NULL(EX_VAR(opline->result.var));
489+
}
490+
}
491+
return;
492+
}
493+
if (EG(exception)) {
494+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
495+
ZVAL_UNDEF(EX_VAR(opline->result.var));
496+
}
497+
return;
498+
}
473499
/* break missing intentionally */
474500
case IS_NULL:
475501
offset_key = ZSTR_EMPTY_ALLOC();
@@ -531,6 +557,8 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim
531557
zend_ulong hval;
532558
zend_string *offset_key;
533559
zval *retval;
560+
zend_execute_data *execute_data;
561+
const zend_op *opline;
534562

535563
if (Z_TYPE_P(dim) == IS_REFERENCE) {
536564
dim = Z_REFVAL_P(dim);
@@ -544,7 +572,31 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim
544572
offset_key = Z_STR_P(dim);
545573
goto str_index;
546574
case IS_UNDEF:
575+
/* The array may be destroyed while throwing the notice.
576+
* Temporarily increase the refcount to detect this situation. */
577+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
578+
GC_ADDREF(ht);
579+
}
580+
execute_data = EG(current_execute_data);
581+
opline = EX(opline);
547582
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
583+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
584+
zend_array_destroy(ht);
585+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
586+
if (EG(exception)) {
587+
ZVAL_UNDEF(EX_VAR(opline->result.var));
588+
} else {
589+
ZVAL_NULL(EX_VAR(opline->result.var));
590+
}
591+
}
592+
return;
593+
}
594+
if (EG(exception)) {
595+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
596+
ZVAL_UNDEF(EX_VAR(opline->result.var));
597+
}
598+
return;
599+
}
548600
/* break missing intentionally */
549601
case IS_NULL:
550602
offset_key = ZSTR_EMPTY_ALLOC();
@@ -616,7 +668,19 @@ static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *d
616668
offset_key = Z_STR_P(dim);
617669
goto str_index;
618670
case IS_UNDEF:
671+
/* The array may be destroyed while throwing the notice.
672+
* Temporarily increase the refcount to detect this situation. */
673+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
674+
GC_ADDREF(ht);
675+
}
619676
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
677+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
678+
zend_array_destroy(ht);
679+
return 0;
680+
}
681+
if (EG(exception)) {
682+
return 0;
683+
}
620684
/* break missing intentionally */
621685
case IS_NULL:
622686
offset_key = ZSTR_EMPTY_ALLOC();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
JIT FETCH_DIM_R: 010
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
set_error_handler(function() {
11+
$GLOBALS['a'] = 0;
12+
});
13+
$a = [$y];
14+
($a[$b]);
15+
($a[17604692317316877817]);
16+
?>
17+
DONE
18+
--EXPECT--
19+
DONE

0 commit comments

Comments
 (0)