Skip to content

Commit 944d653

Browse files
committed
Fix inference for INIT_ARRAY with illegal offset type
Extract assign_dim_array_result_type() helper that can be reused for INIT_ARRAY and implements all this logic correctly. Fixes oss-fuzz 5156868775870464.
1 parent 9346da8 commit 944d653

File tree

2 files changed

+53
-55
lines changed

2 files changed

+53
-55
lines changed

Zend/Optimizer/zend_inference.c

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,6 +2085,41 @@ ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int w
20852085
return tmp;
20862086
}
20872087

2088+
static uint32_t assign_dim_array_result_type(
2089+
uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) {
2090+
uint32_t tmp = 0;
2091+
/* Only add key type if we have a value type. We want to maintain the invariant that a
2092+
* key type exists iff a value type exists even in dead code that may use empty types. */
2093+
if (value_type & (MAY_BE_ANY|MAY_BE_UNDEF)) {
2094+
if (value_type & MAY_BE_UNDEF) {
2095+
value_type |= MAY_BE_NULL;
2096+
}
2097+
if (dim_op_type == IS_UNUSED) {
2098+
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2099+
} else {
2100+
if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
2101+
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2102+
}
2103+
if (dim_type & MAY_BE_STRING) {
2104+
tmp |= MAY_BE_ARRAY_KEY_STRING;
2105+
if (dim_op_type != IS_CONST) {
2106+
// FIXME: numeric string
2107+
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2108+
}
2109+
}
2110+
if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
2111+
tmp |= MAY_BE_ARRAY_KEY_STRING;
2112+
}
2113+
}
2114+
}
2115+
/* Only add value type if we have a key type. It might be that the key type is illegal
2116+
* for arrays. */
2117+
if (tmp & MAY_BE_ARRAY_KEY_ANY) {
2118+
tmp |= (value_type & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
2119+
}
2120+
return tmp;
2121+
}
2122+
20882123
static uint32_t assign_dim_result_type(
20892124
uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) {
20902125
uint32_t tmp = arr_type & ~(MAY_BE_RC1|MAY_BE_RCN);
@@ -2100,35 +2135,7 @@ static uint32_t assign_dim_result_type(
21002135
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
21012136
}
21022137
if (tmp & MAY_BE_ARRAY) {
2103-
/* Only add key type if we have a value type. We want to maintain the invariant that a
2104-
* key type exists iff a value type exists even in dead code that may use empty types. */
2105-
if (value_type & (MAY_BE_ANY|MAY_BE_UNDEF)) {
2106-
if (value_type & MAY_BE_UNDEF) {
2107-
value_type |= MAY_BE_NULL;
2108-
}
2109-
if (dim_op_type == IS_UNUSED) {
2110-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2111-
} else {
2112-
if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
2113-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2114-
}
2115-
if (dim_type & MAY_BE_STRING) {
2116-
tmp |= MAY_BE_ARRAY_KEY_STRING;
2117-
if (dim_op_type != IS_CONST) {
2118-
// FIXME: numeric string
2119-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2120-
}
2121-
}
2122-
if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
2123-
tmp |= MAY_BE_ARRAY_KEY_STRING;
2124-
}
2125-
}
2126-
}
2127-
/* Only add value type if we have a key type. It might be that the key type is illegal
2128-
* for arrays. */
2129-
if (tmp & MAY_BE_ARRAY_KEY_ANY) {
2130-
tmp |= (value_type & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
2131-
}
2138+
tmp |= assign_dim_array_result_type(arr_type, dim_type, value_type, dim_op_type);
21322139
}
21332140
return tmp;
21342141
}
@@ -3181,41 +3188,17 @@ static zend_always_inline int _zend_update_type_info(
31813188
}
31823189
if (ssa_op->result_def >= 0) {
31833190
uint32_t arr_type;
3184-
31853191
if (opline->opcode == ZEND_INIT_ARRAY) {
31863192
arr_type = 0;
31873193
} else {
31883194
arr_type = RES_USE_INFO();
31893195
}
3190-
tmp = MAY_BE_RC1|MAY_BE_ARRAY;
3191-
if (ssa_op->result_use >= 0) {
3192-
tmp |= ssa_var_info[ssa_op->result_use].type;
3193-
}
3196+
tmp = MAY_BE_RC1|MAY_BE_ARRAY|arr_type;
31943197
if (opline->op1_type != IS_UNUSED) {
3195-
tmp |= (t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
3196-
if (t1 & MAY_BE_UNDEF) {
3197-
tmp |= MAY_BE_ARRAY_OF_NULL;
3198-
}
3198+
tmp |= assign_dim_array_result_type(arr_type, t2, t1, opline->op2_type);
31993199
if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
32003200
tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
32013201
}
3202-
if (opline->op2_type == IS_UNUSED) {
3203-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3204-
} else {
3205-
if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
3206-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3207-
}
3208-
if (t2 & (MAY_BE_STRING)) {
3209-
tmp |= MAY_BE_ARRAY_KEY_STRING;
3210-
if (opline->op2_type != IS_CONST) {
3211-
// FIXME: numeric string
3212-
tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3213-
}
3214-
}
3215-
if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
3216-
tmp |= MAY_BE_ARRAY_KEY_STRING;
3217-
}
3218-
}
32193202
}
32203203
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
32213204
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
INIT_ARRAY with illegal offset type
3+
--FILE--
4+
<?php
5+
function test() {
6+
return [new stdClass => null];
7+
}
8+
try {
9+
test();
10+
} catch (TypeError $e) {
11+
echo $e->getMessage(), "\n";
12+
}
13+
?>
14+
--EXPECT--
15+
Illegal offset type

0 commit comments

Comments
 (0)