import python
/** A basic block which terminates in a condition, splitting the subsequent control flow */
class ConditionBlock extends BasicBlock {
ConditionBlock() {
exists(ControlFlowNode succ |
succ = this.getATrueSuccessor() or succ = this.getAFalseSuccessor()
)
}
/** Basic blocks controlled by this condition, i.e. those BBs for which the condition is testIsTrue */
pragma[nomagic]
predicate controls(BasicBlock controlled, boolean testIsTrue) {
/*
* For this block to control the block 'controlled' with 'testIsTrue' the following must be true:
* Execution must have passed through the test i.e. 'this' must strictly dominate 'controlled'.
* Execution must have passed through the 'testIsTrue' edge leaving 'this'.
*
* Although "passed through the true edge" implies that this.getATrueSuccessor() dominates 'controlled',
* the reverse is not true, as flow may have passed through another edge to get to this.getATrueSuccessor()
* so we need to assert that this.getATrueSuccessor() dominates 'controlled' *and* that
* all predecessors of this.getATrueSuccessor() are either this or dominated by this.getATrueSuccessor().
*
* For example, in the following python snippet:
*
* if x:
* controlled
* false_successor
* uncontrolled
*
* false_successor dominates uncontrolled, but not all of its predecessors are this (if x)
* or dominated by itself. Whereas in the following code:
*
* if x:
* while controlled:
* also_controlled
* false_successor
* uncontrolled
*
* the block 'while controlled' is controlled because all of its predecessors are this (if x)
* or (in the case of 'also_controlled') dominated by itself.
*
* The additional constraint on the predecessors of the test successor implies
* that `this` strictly dominates `controlled` so that isn't necessary to check
* directly.
*/
exists(BasicBlock succ |
testIsTrue = true and succ = this.getATrueSuccessor()
or
testIsTrue = false and succ = this.getAFalseSuccessor()
|
succ.dominates(controlled) and
forall(BasicBlock pred | pred.getASuccessor() = succ | pred = this or succ.dominates(pred))
)
}
/** Holds if this condition controls the edge `pred->succ`, i.e. those edges for which the condition is `testIsTrue`. */
predicate controlsEdge(BasicBlock pred, BasicBlock succ, boolean testIsTrue) {
this.controls(pred, testIsTrue) and succ = pred.getASuccessor()
or
pred = this and
(
testIsTrue = true and succ = this.getATrueSuccessor()
or
testIsTrue = false and succ = this.getAFalseSuccessor()
)
}
}