Skip to content

Commit f36f42c

Browse files
Avoid addref/delref where possible
1 parent 34132a7 commit f36f42c

File tree

3 files changed

+45
-133
lines changed

3 files changed

+45
-133
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
No UAF on null offset
3+
--FILE--
4+
<?php
5+
set_error_handler(function($errno, $errstr) {
6+
global $ary;
7+
$ary = null;
8+
echo $errstr;
9+
});
10+
11+
$ary[null] = 1;
12+
13+
echo "\nSuccess\n";
14+
?>
15+
--EXPECTF--
16+
Using null as an array offset is deprecated, use an empty string instead
17+
Success

Zend/zend_execute.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,9 +2631,7 @@ static zend_never_inline uint8_t slow_index_convert(HashTable *ht, const zval *d
26312631
case IS_NULL:
26322632
/* The array may be destroyed while throwing the notice.
26332633
* Temporarily increase the refcount to detect this situation. */
2634-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2635-
GC_ADDREF(ht);
2636-
}
2634+
GC_TRY_ADDREF(ht);
26372635

26382636
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
26392637

@@ -2718,9 +2716,7 @@ static zend_never_inline uint8_t slow_index_convert_w(HashTable *ht, const zval
27182716
case IS_NULL:
27192717
/* The array may be destroyed while throwing the notice.
27202718
* Temporarily increase the refcount to detect this situation. */
2721-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
2722-
GC_ADDREF(ht);
2723-
}
2719+
GC_TRY_ADDREF(ht);
27242720

27252721
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
27262722

@@ -3226,9 +3222,7 @@ static zend_never_inline zval* ZEND_FASTCALL zend_find_array_dim_slow(HashTable
32263222
null_undef_idx:
32273223
/* The array may be destroyed while throwing the notice.
32283224
* Temporarily increase the refcount to detect this situation. */
3229-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
3230-
GC_ADDREF(ht);
3231-
}
3225+
GC_TRY_ADDREF(ht);
32323226

32333227
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
32343228

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 25 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -500,33 +500,16 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim,
500500
}
501501
ZEND_FALLTHROUGH;
502502
case IS_NULL:
503-
/* The array may be destroyed while throwing the notice.
504-
* Temporarily increase the refcount to detect this situation. */
505-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
506-
GC_ADDREF(ht);
503+
retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
504+
if (!retval) {
505+
ZVAL_NULL(result);
506+
} else {
507+
ZVAL_COPY_DEREF(result, retval);
507508
}
508-
execute_data = EG(current_execute_data);
509-
opline = EX(opline);
509+
510510
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
511-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
512-
zend_array_destroy(ht);
513-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
514-
if (EG(exception)) {
515-
ZVAL_UNDEF(EX_VAR(opline->result.var));
516-
} else {
517-
ZVAL_NULL(EX_VAR(opline->result.var));
518-
}
519-
}
520-
return;
521-
}
522-
if (EG(exception)) {
523-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
524-
ZVAL_UNDEF(EX_VAR(opline->result.var));
525-
}
526-
return;
527-
}
528-
offset_key = ZSTR_EMPTY_ALLOC();
529-
goto str_index;
511+
512+
return;
530513
case IS_DOUBLE:
531514
hval = zend_dval_to_lval(Z_DVAL_P(dim));
532515
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
@@ -667,33 +650,16 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim
667650
}
668651
ZEND_FALLTHROUGH;
669652
case IS_NULL:
670-
/* The array may be destroyed while throwing the notice.
671-
* Temporarily increase the refcount to detect this situation. */
672-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
673-
GC_ADDREF(ht);
653+
retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
654+
if (!retval) {
655+
ZVAL_NULL(result);
656+
} else {
657+
ZVAL_COPY_DEREF(result, retval);
674658
}
675-
execute_data = EG(current_execute_data);
676-
opline = EX(opline);
659+
677660
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
678-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
679-
zend_array_destroy(ht);
680-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
681-
if (EG(exception)) {
682-
ZVAL_UNDEF(EX_VAR(opline->result.var));
683-
} else {
684-
ZVAL_NULL(EX_VAR(opline->result.var));
685-
}
686-
}
687-
return;
688-
}
689-
if (EG(exception)) {
690-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
691-
ZVAL_UNDEF(EX_VAR(opline->result.var));
692-
}
693-
return;
694-
}
695-
offset_key = ZSTR_EMPTY_ALLOC();
696-
goto str_index;
661+
662+
return;
697663
case IS_DOUBLE:
698664
hval = zend_dval_to_lval(Z_DVAL_P(dim));
699665
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
@@ -820,21 +786,10 @@ static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *d
820786
}
821787
ZEND_FALLTHROUGH;
822788
case IS_NULL:
823-
/* The array may be destroyed while throwing the notice.
824-
* Temporarily increase the refcount to detect this situation. */
825-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
826-
GC_ADDREF(ht);
827-
}
789+
retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
828790
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
829-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
830-
zend_array_destroy(ht);
831-
return 0;
832-
}
833-
if (EG(exception)) {
834-
return 0;
835-
}
836-
offset_key = ZSTR_EMPTY_ALLOC();
837-
goto str_index;
791+
792+
return Z_TYPE_P(retval) > IS_NULL;
838793
case IS_DOUBLE:
839794
hval = zend_dval_to_lval(Z_DVAL_P(dim));
840795
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
@@ -941,35 +896,10 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *di
941896
}
942897
ZEND_FALLTHROUGH;
943898
case IS_NULL:
944-
/* The array may be destroyed while throwing the notice.
945-
* Temporarily increase the refcount to detect this situation. */
946-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
947-
GC_ADDREF(ht);
948-
}
949-
execute_data = EG(current_execute_data);
950-
opline = EX(opline);
899+
retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
951900
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
952-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
953-
if (!GC_REFCOUNT(ht)) {
954-
zend_array_destroy(ht);
955-
}
956-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
957-
if (EG(exception)) {
958-
ZVAL_UNDEF(EX_VAR(opline->result.var));
959-
} else {
960-
ZVAL_NULL(EX_VAR(opline->result.var));
961-
}
962-
}
963-
return NULL;
964-
}
965-
if (EG(exception)) {
966-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
967-
ZVAL_UNDEF(EX_VAR(opline->result.var));
968-
}
969-
return NULL;
970-
}
971-
offset_key = ZSTR_EMPTY_ALLOC();
972-
goto str_index;
901+
902+
return retval;
973903
case IS_DOUBLE:
974904
hval = zend_dval_to_lval(Z_DVAL_P(dim));
975905
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
@@ -1101,39 +1031,10 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim
11011031
}
11021032
ZEND_FALLTHROUGH;
11031033
case IS_NULL:
1104-
/* The array may be destroyed while throwing the notice.
1105-
* Temporarily increase the refcount to detect this situation. */
1106-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1107-
GC_ADDREF(ht);
1108-
}
1109-
execute_data = EG(current_execute_data);
1110-
opline = EX(opline);
1034+
retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
11111035
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
1112-
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
1113-
if (!GC_REFCOUNT(ht)) {
1114-
zend_array_destroy(ht);
1115-
}
1116-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1117-
if (EG(exception)) {
1118-
ZVAL_UNDEF(EX_VAR(opline->result.var));
1119-
} else {
1120-
ZVAL_NULL(EX_VAR(opline->result.var));
1121-
}
1122-
}
1123-
if (opline->opcode == ZEND_ASSIGN_DIM
1124-
&& ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) {
1125-
zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
1126-
}
1127-
return NULL;
1128-
}
1129-
if (EG(exception)) {
1130-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1131-
ZVAL_UNDEF(EX_VAR(opline->result.var));
1132-
}
1133-
return NULL;
1134-
}
1135-
offset_key = ZSTR_EMPTY_ALLOC();
1136-
goto str_index;
1036+
1037+
return retval;
11371038
case IS_DOUBLE:
11381039
hval = zend_dval_to_lval(Z_DVAL_P(dim));
11391040
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {

0 commit comments

Comments
 (0)