From 83738281eb9f2577eda1c76a6acfe644d6fcc6c1 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 30 Oct 2020 15:48:03 +0100 Subject: Fix SSA integrity violation for type inference in dead code 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 | 18 ++++++++++++++++ ext/opcache/Optimizer/zend_inference.c | 34 +++++++++++++++++-------------- 2 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 Zend/tests/dead_array_type_inference.phpt diff --git a/Zend/tests/dead_array_type_inference.phpt b/Zend/tests/dead_array_type_inference.phpt new file mode 100644 index 0000000000..51f9b05816 --- /dev/null +++ b/Zend/tests/dead_array_type_inference.phpt @@ -0,0 +1,18 @@ +--TEST-- +Make sure type inference upholds invariants for dead arrays +--FILE-- + +--EXPECTF-- +Notice: Undefined variable: a in %s on line %d + +Warning: Invalid argument supplied for foreach() in %s on line %d diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index fa494794cb..368f68108d 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -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 -- cgit v1.2.1