From ddf89102377a0603d76936a9b0d5a6dafd5bc229 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 27 Sep 2021 11:24:52 +0200 Subject: [PATCH] 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. --- Zend/tests/unreachable_phi_cycle.phpt | 15 +++++++++++++++ ext/opcache/Optimizer/dce.c | 10 ++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/unreachable_phi_cycle.phpt diff --git a/Zend/tests/unreachable_phi_cycle.phpt b/Zend/tests/unreachable_phi_cycle.phpt new file mode 100644 index 00000000000..84bfec214bb --- /dev/null +++ b/Zend/tests/unreachable_phi_cycle.phpt @@ -0,0 +1,15 @@ +--TEST-- +Unreachable phi cycle +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $i in %s on line %d diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c index 9821d9350e0..0eddff4a1d5 100644 --- a/ext/opcache/Optimizer/dce.c +++ b/ext/opcache/Optimizer/dce.c @@ -436,13 +436,19 @@ static inline int get_common_phi_source(zend_ssa *ssa, zend_ssa_phi *phi) { int common_source = -1; int source; FOREACH_PHI_SOURCE(phi, source) { + if (source == phi->ssa_var) { + continue; + } if (common_source == -1) { common_source = source; - } else if (common_source != source && source != phi->ssa_var) { + } else if (common_source != source) { return -1; } } FOREACH_PHI_SOURCE_END(); - ZEND_ASSERT(common_source != -1); + + /* If all sources are phi->ssa_var this phi must be in an unreachable cycle. + * We can't easily drop the phi in that case, as we don't have something to replace it with. + * Ideally SCCP would eliminate the whole cycle. */ return common_source; }