Skip to content

Commit ad401e9

Browse files
committed
C++: Copy and adjust Java's correctness argumnt
Instead of a vague reference to a code comment for another language, the `controlsBlock` predicate now has the whole comment in it directly. I've adjusted the wording so it should be reasonably correct for C/C++. As with the other comments in this file, I don't distinguish between the condition and its block. I think that makes the explanation clearer without losing any detail we care about. To make the code fit the wording of the comment, I changed the `hasBranchEdge/2` predicate into `getBranchSuccessor/1`.
1 parent 4642037 commit ad401e9

File tree

1 file changed

+44
-9
lines changed

1 file changed

+44
-9
lines changed

cpp/ql/src/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)