Skip to content

Commit ddf8910

Browse files
committed
Fix DCE of unreachable phi in cycle
We can't remove a trivial phi of the form x = phi(x), because we don't have a replacement value. We could drop the whole block though. SCCP would normally do this, but in this particular case we only determine non-reachability based on type information. Fixes oss-fuzz #39316.
1 parent 038bc27 commit ddf8910

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

Zend/tests/unreachable_phi_cycle.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Unreachable phi cycle
3+
--FILE--
4+
<?php
5+
// The inner loop is dead, but SCCP reachability analysis doesn't realize this,
6+
// as this is determined based on type information.
7+
function test() {
8+
for (; $i--;) {
9+
for(; x;);
10+
}
11+
}
12+
test();
13+
?>
14+
--EXPECTF--
15+
Warning: Undefined variable $i in %s on line %d

ext/opcache/Optimizer/dce.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,19 @@ static inline int get_common_phi_source(zend_ssa *ssa, zend_ssa_phi *phi) {
436436
int common_source = -1;
437437
int source;
438438
FOREACH_PHI_SOURCE(phi, source) {
439+
if (source == phi->ssa_var) {
440+
continue;
441+
}
439442
if (common_source == -1) {
440443
common_source = source;
441-
} else if (common_source != source && source != phi->ssa_var) {
444+
} else if (common_source != source) {
442445
return -1;
443446
}
444447
} FOREACH_PHI_SOURCE_END();
445-
ZEND_ASSERT(common_source != -1);
448+
449+
/* If all sources are phi->ssa_var this phi must be in an unreachable cycle.
450+
* We can't easily drop the phi in that case, as we don't have something to replace it with.
451+
* Ideally SCCP would eliminate the whole cycle. */
446452
return common_source;
447453
}
448454

0 commit comments

Comments
 (0)