summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-17 10:20:23 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-17 10:20:23 +0100
commit9cfb5261e4b48e0520fc7e085e6eb189eeb33b3d (patch)
tree73802c6f49164ef130d0bed6ead35c3ee03d4db8
parent0425a6697a21327880e36975c733bba2b6a6890a (diff)
parentdf7417d1275c53d9b38d5c3ad5d9beb263a21e08 (diff)
downloadphp-git-9cfb5261e4b48e0520fc7e085e6eb189eeb33b3d.tar.gz
Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4: Fix incorrectly optimized out live range
-rw-r--r--Zend/tests/live_range_phi_leak.phpt19
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c18
2 files changed, 33 insertions, 4 deletions
diff --git a/Zend/tests/live_range_phi_leak.phpt b/Zend/tests/live_range_phi_leak.phpt
new file mode 100644
index 0000000000..f072584053
--- /dev/null
+++ b/Zend/tests/live_range_phi_leak.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Missing live range if part of phi
+--FILE--
+<?php
+function doThrow() {
+ throw new Exception("Test");
+}
+function test($k) {
+ // The 0 gives the QM_ASSIGN a non-refcounted type.
+ $res[$k ? $k : 0] = doThrow();
+}
+try {
+ test(new stdClass);
+} catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+}
+?>
+--EXPECT--
+Test
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index b0efcc9026..c80992ed8d 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -1350,11 +1350,21 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
static zend_bool needs_live_range(zend_op_array *op_array, zend_op *def_opline) {
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
zend_ssa_op *ssa_op = &func_info->ssa.ops[def_opline - op_array->opcodes];
- if (ssa_op->result_def >= 0) {
- uint32_t type = func_info->ssa.var_info[ssa_op->result_def].type;
- return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
+ int ssa_var = ssa_op->result_def;
+ if (ssa_var < 0) {
+ /* Be conservative. */
+ return 1;
}
- return 1;
+
+ /* If the variable is used by a PHI, this may be the assignment of the final branch of a
+ * ternary/etc structure. While this is where the live range starts, the value from the other
+ * branch may also be used. As such, use the type of the PHI node for the following check. */
+ if (func_info->ssa.vars[ssa_var].phi_use_chain) {
+ ssa_var = func_info->ssa.vars[ssa_var].phi_use_chain->ssa_var;
+ }
+
+ uint32_t type = func_info->ssa.var_info[ssa_var].type;
+ return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
}
void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context)