diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll index 29580c2c507..1a5a30d1454 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticSSA.qll @@ -70,6 +70,27 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP // Conservatively assume that every edge is a back edge if we don't have dominance information. ( phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or + irreducibleSccEdge(phi.getBasicBlock(), edge.getOrigBlock()) or not edge.getOrigBlock().hasDominanceInformation() ) } + +/** + * Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow + * graph. + * + * An ireducible control flow graph is one where the usual dominance-based back edge detection does + * not work, because there is a cycle with multiple entry points, meaning there are + * mutually-reachable basic blocks where neither dominates the other. For such a graph, we first + * remove all detectable back-edges using the normal condition that the predecessor block is + * dominated by the successor block, then mark all edges in a cycle in the resulting graph as back + * edges. + */ +private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) { + trimmedEdge(b1, b2) and trimmedEdge+(b2, b1) +} + +private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) { + pred.getASuccessor() = succ and + not succ.bbDominates(pred) +} diff --git a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp index 95e6474124a..1e28d858b78 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/test.cpp +++ b/cpp/ql/test/library-tests/ir/range-analysis/test.cpp @@ -70,3 +70,27 @@ int f4(int x) { } } } + +// No interesting ranges to check here - this irreducible CFG caused an infinite loop due to back edge detection +void gotoLoop(bool b1, bool b2) +{ + int j; + + if (b1) + return; + + if (!b2) + { + for (j = 0; j < 10; ++j) + { + goto main_decode_loop; + } + } + else + { + for (j = 0; j < 10; ++j) + { + main_decode_loop: + } + } +} \ No newline at end of file