From df7417d1275c53d9b38d5c3ad5d9beb263a21e08 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 17 Nov 2020 10:18:37 +0100 Subject: Fix incorrectly optimized out live range For x ? y : z style structures, the live range starts at z, but may also hold the value of y. Make sure that the refcounting check takes this into account, by checking the type of a potential phi user. --- Zend/tests/live_range_phi_leak.phpt | 19 +++++++++++++++++++ ext/opcache/Optimizer/zend_optimizer.c | 18 ++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/live_range_phi_leak.phpt 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-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Test diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 0349d0ffbe..7871fa3c8e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -1312,11 +1312,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; } #endif -- cgit v1.2.1