]> granicus.if.org Git - php/commitdiff
Fix a couple of ASSIGN_DIM/OBJ inference bugs
authorNikita Popov <nikic@php.net>
Sat, 24 Sep 2016 19:26:17 +0000 (21:26 +0200)
committerNikita Popov <nikic@php.net>
Sat, 24 Sep 2016 20:43:27 +0000 (22:43 +0200)
Account for possible null return values better.

Zend/tests/assign_dim_obj_null_return.phpt [new file with mode: 0644]
ext/opcache/Optimizer/zend_inference.c

diff --git a/Zend/tests/assign_dim_obj_null_return.phpt b/Zend/tests/assign_dim_obj_null_return.phpt
new file mode 100644 (file)
index 0000000..e833ef3
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+Various null return conditions of dim/obj assignments
+--FILE--
+<?php
+
+function test() {
+    $array = [PHP_INT_MAX => 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
index 4e7db1a75b38dfa411053e710df7ac39fec2c493..5abab01ac41ee4d4dde358c0c598d727469b1570 100644 (file)
@@ -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) {