@@ -305,13 +305,13 @@ class IRGuardCondition extends Instruction {
305305 pred .getASuccessor ( ) = succ and
306306 controls ( pred , testIsTrue )
307307 or
308- hasBranchEdge ( succ , testIsTrue ) and
308+ succ = getBranchSuccessor ( testIsTrue ) and
309309 branch .getCondition ( ) = this and
310310 branch .getBlock ( ) = pred
311311 }
312312
313313 /**
314- * Holds if `branch` jumps directly to `succ` when this condition is `testIsTrue`.
314+ * Gets the block to which `branch` jumps directly when this condition is `testIsTrue`.
315315 *
316316 * This predicate is intended to help with situations in which an inference can only be made
317317 * based on an edge between a block with multiple successors and a block with multiple
@@ -325,14 +325,14 @@ class IRGuardCondition extends Instruction {
325325 * return x;
326326 * ```
327327 */
328- private predicate hasBranchEdge ( IRBlock succ , boolean testIsTrue ) {
328+ private IRBlock getBranchSuccessor ( boolean testIsTrue ) {
329329 branch .getCondition ( ) = this and
330330 (
331331 testIsTrue = true and
332- succ .getFirstInstruction ( ) = branch .getTrueSuccessor ( )
332+ result .getFirstInstruction ( ) = branch .getTrueSuccessor ( )
333333 or
334334 testIsTrue = false and
335- succ .getFirstInstruction ( ) = branch .getFalseSuccessor ( )
335+ result .getFirstInstruction ( ) = branch .getFalseSuccessor ( )
336336 )
337337 }
338338
@@ -406,11 +406,46 @@ class IRGuardCondition extends Instruction {
406406 */
407407 private predicate controlsBlock ( IRBlock controlled , boolean testIsTrue ) {
408408 not isUnreachedBlock ( controlled ) and
409- // The following implementation is ported from `controls` in Java's
410- // `Guards.qll`. See that file (at 398678a28) for further explanation and
411- // correctness arguments.
409+ //
410+ // For this block to control the block `controlled` with `testIsTrue` the
411+ // following must hold: Execution must have passed through the test; that
412+ // is, `this` must strictly dominate `controlled`. Execution must have
413+ // passed through the `testIsTrue` edge leaving `this`.
414+ //
415+ // Although "passed through the true edge" implies that
416+ // `getBranchSuccessor(true)` dominates `controlled`, the reverse is not
417+ // true, as flow may have passed through another edge to get to
418+ // `getBranchSuccessor(true)`, so we need to assert that
419+ // `getBranchSuccessor(true)` dominates `controlled` *and* that all
420+ // predecessors of `getBranchSuccessor(true)` are either `this` or
421+ // dominated by `getBranchSuccessor(true)`.
422+ //
423+ // For example, in the following snippet:
424+ //
425+ // if (x)
426+ // controlled;
427+ // false_successor;
428+ // uncontrolled;
429+ //
430+ // `false_successor` dominates `uncontrolled`, but not all of its
431+ // predecessors are `this` (`if (x)`) or dominated by itself. Whereas in
432+ // the following code:
433+ //
434+ // if (x)
435+ // while (controlled)
436+ // also_controlled;
437+ // false_successor;
438+ // uncontrolled;
439+ //
440+ // the block `while (controlled)` is controlled because all of its
441+ // predecessors are `this` (`if (x)`) or (in the case of `also_controlled`)
442+ // dominated by itself.
443+ //
444+ // The additional constraint on the predecessors of the test successor implies
445+ // that `this` strictly dominates `controlled` so that isn't necessary to check
446+ // directly.
412447 exists ( IRBlock succ |
413- this .hasBranchEdge ( succ , testIsTrue ) and
448+ succ = this .getBranchSuccessor ( testIsTrue ) and
414449 this .hasDominatingEdgeTo ( succ ) and
415450 succ .dominates ( controlled )
416451 )
0 commit comments