Improve type narrowing fix

We need to explicitly model the null return type for property
accesses on non-objects.
This commit is contained in:
Nikita Popov 2022-04-10 11:13:55 +02:00
parent 323f3c6914
commit c72e9621ce
2 changed files with 51 additions and 172 deletions

View file

@ -1764,11 +1764,6 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
(ssa_var_info[__var].type & MAY_BE_REF) \
== (__type & MAY_BE_REF)); \
if (ssa_var_info[__var].type & ~__type) { \
if ((ssa_var_info[__var].type & ~__type & \
~(MAY_BE_RC1|MAY_BE_RCN)) == 0) { \
ssa_var_info[__var].type |= __type; \
break; \
} \
emit_type_narrowing_warning(op_array, ssa, __var); \
return FAILURE; \
} \
@ -3375,33 +3370,40 @@ static zend_always_inline int _zend_update_type_info(
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
if (ssa_op->result_def >= 0) {
zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
uint32_t tmp = 0;
ce = NULL;
if (opline->op1_type != IS_UNUSED
&& (t1 & (MAY_BE_ANY | MAY_BE_UNDEF) & ~MAY_BE_OBJECT)) {
tmp |= MAY_BE_NULL;
}
if (opline->op1_type == IS_UNUSED || (t1 & MAY_BE_OBJECT)) {
zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
tmp |= zend_fetch_prop_type(script, prop_info, &ce);
if (opline->result_type == IS_VAR) {
tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
} else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) {
zend_class_entry *ce = NULL;
tmp = zend_fetch_prop_type(script, prop_info, &ce);
if (opline->result_type == IS_VAR) {
tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
} else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) {
zend_class_entry *ce = NULL;
if (opline->op1_type == IS_UNUSED) {
ce = op_array->scope;
} else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
ce = ssa->var_info[ssa_op->op1_use].ce;
}
if (prop_info) {
/* FETCH_OBJ_R/IS for plain property increments reference counter,
so it can't be 1 */
if (ce && !ce->create_object && !result_may_be_separated(ssa, ssa_op)) {
tmp &= ~MAY_BE_RC1;
if (opline->op1_type == IS_UNUSED) {
ce = op_array->scope;
} else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
ce = ssa->var_info[ssa_op->op1_use].ce;
}
} else {
if (ce && !ce->create_object && !ce->__get && !result_may_be_separated(ssa, ssa_op)) {
tmp &= ~MAY_BE_RC1;
if (prop_info) {
/* FETCH_OBJ_R/IS for plain property increments reference counter,
so it can't be 1 */
if (ce && !ce->create_object && !result_may_be_separated(ssa, ssa_op)) {
tmp &= ~MAY_BE_RC1;
}
} else {
if (ce && !ce->create_object && !ce->__get && !result_may_be_separated(ssa, ssa_op)) {
tmp &= ~MAY_BE_RC1;
}
}
if (opline->opcode == ZEND_FETCH_OBJ_IS) {
/* IS check may return null for uninitialized typed property. */
tmp |= MAY_BE_NULL;
}
}
if (opline->opcode == ZEND_FETCH_OBJ_IS) {
/* IS check may return null for uninitialized typed property. */
tmp |= MAY_BE_NULL;
}
}
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);

View file

@ -7,157 +7,34 @@ opcache.optimization_level=-1
--FILE--
<?php
function test() {
$j = 0;
for ($i = 0; $i = 10; $i++) {
$e;
$a = $a;
$obj->$e;
$i += $a;
$j++;
$e;
$a == $Z + $a .= $i+= $a;
$j++;
$e;
$a == $Z + $j++;
$e;
$a == $Z + $a = $a + $b = $i += $a;
for ($i = 0; $i < 2; $i++) {
$obj->x;
$obj = new stdClass;
$obj->prop1 = set_error_handler(function () {
$$GLOBALS['a'] = null;
});
$obj->$a .= $i += $a;
$obj = new stdClass;
$obj->prop1 = $j++;
$e;
$a == $Z + $a = $a + $j++;
$e;
$a == $Z + $a = $a + $b = $aa = $a;
}
}
test();
class Test {
public int $x = 1;
}
function test2() {
for ($i = 0; $i < 2; $i++) {
$obj->x;
$obj = new Test;
}
}
test2();
?>
DONE
--EXPECTF--
Warning: Undefined variable $a in %sinference_001.php on line 6
Warning: Undefined variable $obj in %s on line %d
Warning: Undefined variable $obj in %sinference_001.php on line 7
Warning: Attempt to read property "x" on null in %s on line %d
Warning: Undefined variable $e in %sinference_001.php on line 7
Warning: Undefined property: stdClass::$x in %s on line %d
Warning: Attempt to read property "" on null in %sinference_001.php on line 7
Warning: Undefined variable $obj in %s on line %d
Warning: Undefined variable $Z in %sinference_001.php on line 11
Warning: Undefined variable $Z in %sinference_001.php on line 14
Warning: Undefined variable $Z in %sinference_001.php on line 16
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Warning: Array to string conversion in %sinference_001.php on line 19
Fatal error: Uncaught TypeError: Unsupported operand types: null + string in %sinference_001.php:11
Stack trace:
#0 %sinference_001.php(30): test()
#1 {main}
thrown in %sinference_001.php on line 11
Warning: Attempt to read property "x" on null in %s on line %d
DONE