From: Nikita Popov Date: Sat, 24 Sep 2016 19:26:17 +0000 (+0200) Subject: Fix a couple of ASSIGN_DIM/OBJ inference bugs X-Git-Tag: php-7.1.0RC3~31 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c7651c23960f508ad0166bfe4c89bb5c1946324a;p=php Fix a couple of ASSIGN_DIM/OBJ inference bugs Account for possible null return values better. --- diff --git a/Zend/tests/assign_dim_obj_null_return.phpt b/Zend/tests/assign_dim_obj_null_return.phpt new file mode 100644 index 0000000000..e833ef3591 --- /dev/null +++ b/Zend/tests/assign_dim_obj_null_return.phpt @@ -0,0 +1,56 @@ +--TEST-- +Various null return conditions of dim/obj assignments +--FILE-- + 42]; + $true = true; + + var_dump($array[] = 123); + var_dump($array[[]] = 123); + var_dump($array[new stdClass] = 123); + var_dump($true[123] = 456); + + var_dump($array[] += 123); + var_dump($array[[]] += 123); + var_dump($array[new stdClass] += 123); + var_dump($true[123] += 456); + + var_dump($true->foo = 123); + var_dump($true->foo += 123); +} + +test(); + +?> +--EXPECTF-- +Warning: Cannot add element to the array as the next element is already occupied in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Cannot use a scalar value as an array in %s on line %d +NULL + +Warning: Cannot add element to the array as the next element is already occupied in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Illegal offset type in %s on line %d +NULL + +Warning: Cannot use a scalar value as an array in %s on line %d +NULL + +Warning: Attempt to assign property of non-object in %s on line %d +NULL + +Warning: Attempt to assign property of non-object in %s on line %d +NULL diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 4e7db1a75b..5abab01ac4 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2584,6 +2584,28 @@ static void zend_update_type_info(const zend_op_array *op_array, UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); } if (ssa_ops[i].result_def >= 0) { + if (opline->extended_value == ZEND_ASSIGN_DIM) { + if (opline->op2_type == IS_UNUSED) { + /* When appending to an array and the LONG_MAX key is already used + * null will be returned. */ + tmp |= MAY_BE_NULL; + } + if (t2 & (MAY_BE_ARRAY | MAY_BE_OBJECT)) { + /* Arrays and objects cannot be used as keys. */ + tmp |= MAY_BE_NULL; + } + if (t1 & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) { + /* null and false are implicitly converted to array, anything else + * results in a null return value. */ + tmp |= MAY_BE_NULL; + } + } else if (opline->extended_value == ZEND_ASSIGN_OBJ) { + if (orig & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT))) { + /* null and false (and empty string) are implicitly converted to object, + * anything else results in a null return value. */ + tmp |= MAY_BE_NULL; + } + } UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); } break; @@ -2709,6 +2731,21 @@ static void zend_update_type_info(const zend_op_array *op_array, } if (t1 & (MAY_BE_ANY - MAY_BE_STRING)) { tmp |= (OP1_DATA_INFO() & (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF)); + + if (opline->op2_type == IS_UNUSED) { + /* When appending to an array and the LONG_MAX key is already used + * null will be returned. */ + tmp |= MAY_BE_NULL; + } + if (t2 & (MAY_BE_ARRAY | MAY_BE_OBJECT)) { + /* Arrays and objects cannot be used as keys. */ + tmp |= MAY_BE_NULL; + } + if (t1 & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) { + /* null and false are implicitly converted to array, anything else + * results in a null return value. */ + tmp |= MAY_BE_NULL; + } } tmp |= MAY_BE_RC1 | MAY_BE_RCN; if (t1 & MAY_BE_OBJECT) {