@@ -305,13 +305,13 @@ class IRGuardCondition extends Instruction {
305
305
pred .getASuccessor ( ) = succ and
306
306
controls ( pred , testIsTrue )
307
307
or
308
- hasBranchEdge ( succ , testIsTrue ) and
308
+ succ = getBranchSuccessor ( testIsTrue ) and
309
309
branch .getCondition ( ) = this and
310
310
branch .getBlock ( ) = pred
311
311
}
312
312
313
313
/**
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`.
315
315
*
316
316
* This predicate is intended to help with situations in which an inference can only be made
317
317
* based on an edge between a block with multiple successors and a block with multiple
@@ -325,14 +325,14 @@ class IRGuardCondition extends Instruction {
325
325
* return x;
326
326
* ```
327
327
*/
328
- private predicate hasBranchEdge ( IRBlock succ , boolean testIsTrue ) {
328
+ private IRBlock getBranchSuccessor ( boolean testIsTrue ) {
329
329
branch .getCondition ( ) = this and
330
330
(
331
331
testIsTrue = true and
332
- succ .getFirstInstruction ( ) = branch .getTrueSuccessor ( )
332
+ result .getFirstInstruction ( ) = branch .getTrueSuccessor ( )
333
333
or
334
334
testIsTrue = false and
335
- succ .getFirstInstruction ( ) = branch .getFalseSuccessor ( )
335
+ result .getFirstInstruction ( ) = branch .getFalseSuccessor ( )
336
336
)
337
337
}
338
338
@@ -406,11 +406,46 @@ class IRGuardCondition extends Instruction {
406
406
*/
407
407
private predicate controlsBlock ( IRBlock controlled , boolean testIsTrue ) {
408
408
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.
412
447
exists ( IRBlock succ |
413
- this .hasBranchEdge ( succ , testIsTrue ) and
448
+ succ = this .getBranchSuccessor ( testIsTrue ) and
414
449
this .hasDominatingEdgeTo ( succ ) and
415
450
succ .dominates ( controlled )
416
451
)
0 commit comments