Skip to content

Commit df7417d

Browse files
committed
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.
1 parent 7877389 commit df7417d

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

Zend/tests/live_range_phi_leak.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Missing live range if part of phi
3+
--FILE--
4+
<?php
5+
function doThrow() {
6+
throw new Exception("Test");
7+
}
8+
function test($k) {
9+
// The 0 gives the QM_ASSIGN a non-refcounted type.
10+
$res[$k ? $k : 0] = doThrow();
11+
}
12+
try {
13+
test(new stdClass);
14+
} catch (Exception $e) {
15+
echo $e->getMessage(), "\n";
16+
}
17+
?>
18+
--EXPECT--
19+
Test

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,11 +1312,21 @@ static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
13121312
static zend_bool needs_live_range(zend_op_array *op_array, zend_op *def_opline) {
13131313
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
13141314
zend_ssa_op *ssa_op = &func_info->ssa.ops[def_opline - op_array->opcodes];
1315-
if (ssa_op->result_def >= 0) {
1316-
uint32_t type = func_info->ssa.var_info[ssa_op->result_def].type;
1317-
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
1315+
int ssa_var = ssa_op->result_def;
1316+
if (ssa_var < 0) {
1317+
/* Be conservative. */
1318+
return 1;
13181319
}
1319-
return 1;
1320+
1321+
/* If the variable is used by a PHI, this may be the assignment of the final branch of a
1322+
* ternary/etc structure. While this is where the live range starts, the value from the other
1323+
* branch may also be used. As such, use the type of the PHI node for the following check. */
1324+
if (func_info->ssa.vars[ssa_var].phi_use_chain) {
1325+
ssa_var = func_info->ssa.vars[ssa_var].phi_use_chain->ssa_var;
1326+
}
1327+
1328+
uint32_t type = func_info->ssa.var_info[ssa_var].type;
1329+
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
13201330
}
13211331
#endif
13221332

0 commit comments

Comments
 (0)