]> granicus.if.org Git - php/commitdiff
Fix SSA integrity violation for type inference in dead code
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 30 Oct 2020 14:48:03 +0000 (15:48 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 30 Oct 2020 14:52:10 +0000 (15:52 +0100)
The foreach body can never be executed and thus may contain empty
types. We should still uphold our SSA integrity invariants in that
case.

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

diff --git a/Zend/tests/dead_array_type_inference.phpt b/Zend/tests/dead_array_type_inference.phpt
new file mode 100644 (file)
index 0000000..51f9b05
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+Make sure type inference upholds invariants for dead arrays
+--FILE--
+<?php
+
+function test() {
+    foreach ($a as $v) {
+        $b[] = $v;
+    }
+}
+
+test();
+
+?>
+--EXPECTF--
+Notice: Undefined variable: a in %s on line %d
+
+Warning: Invalid argument supplied for foreach() in %s on line %d
index fa494794cb2b6e29d8d0d38dca039c667fac73e4..368f68108dc66569e4881215328488adeb19172e 100644 (file)
@@ -2106,24 +2106,28 @@ static uint32_t assign_dim_result_type(
                tmp |= MAY_BE_RC1 | MAY_BE_RCN;
        }
        if (tmp & MAY_BE_ARRAY) {
-               if (value_type & MAY_BE_UNDEF) {
-                       tmp |= MAY_BE_ARRAY_OF_NULL;
-               }
-               if (dim_op_type == IS_UNUSED) {
-                       tmp |= MAY_BE_ARRAY_KEY_LONG;
-               } else {
-                       if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
-                               tmp |= MAY_BE_ARRAY_KEY_LONG;
+               /* Only add key type if we have a value type. We want to maintain the invariant that a
+                * key type exists iff a value type exists even in dead code that may use empty types. */
+               if (value_type & (MAY_BE_ANY|MAY_BE_UNDEF)) {
+                       if (value_type & MAY_BE_UNDEF) {
+                               tmp |= MAY_BE_ARRAY_OF_NULL;
                        }
-                       if (dim_type & MAY_BE_STRING) {
-                               tmp |= MAY_BE_ARRAY_KEY_STRING;
-                               if (dim_op_type != IS_CONST) {
-                                       // FIXME: numeric string
+                       if (dim_op_type == IS_UNUSED) {
+                               tmp |= MAY_BE_ARRAY_KEY_LONG;
+                       } else {
+                               if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
                                        tmp |= MAY_BE_ARRAY_KEY_LONG;
                                }
-                       }
-                       if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
-                               tmp |= MAY_BE_ARRAY_KEY_STRING;
+                               if (dim_type & MAY_BE_STRING) {
+                                       tmp |= MAY_BE_ARRAY_KEY_STRING;
+                                       if (dim_op_type != IS_CONST) {
+                                               // FIXME: numeric string
+                                               tmp |= MAY_BE_ARRAY_KEY_LONG;
+                                       }
+                               }
+                               if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
+                                       tmp |= MAY_BE_ARRAY_KEY_STRING;
+                               }
                        }
                }
                /* Only add value type if we have a key type. It might be that the key type is illegal