diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-17 10:20:23 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-17 10:20:23 +0100 |
commit | 9cfb5261e4b48e0520fc7e085e6eb189eeb33b3d (patch) | |
tree | 73802c6f49164ef130d0bed6ead35c3ee03d4db8 | |
parent | 0425a6697a21327880e36975c733bba2b6a6890a (diff) | |
parent | df7417d1275c53d9b38d5c3ad5d9beb263a21e08 (diff) | |
download | php-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.phpt | 19 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 18 |
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) |