diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-17 10:18:37 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-17 10:19:57 +0100 |
commit | df7417d1275c53d9b38d5c3ad5d9beb263a21e08 (patch) | |
tree | 402cc77bd9597b54db07906a0703e847bc005843 /ext | |
parent | 78773890f6b0d82b29e0b869f3f3b22174cea217 (diff) | |
download | php-git-df7417d1275c53d9b38d5c3ad5d9beb263a21e08.tar.gz |
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.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 18 |
1 files changed, 14 insertions, 4 deletions
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 |