44
55import csharp
66private import ControlFlow:: SuccessorTypes
7+ private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as CfgImpl
8+ import CfgImpl:: BasicBlock as BasicBlockImpl
79
8- /**
9- * A basic block, that is, a maximal straight-line sequence of control flow nodes
10- * without branches or joins.
11- */
12- class BasicBlock extends TBasicBlockStart {
13- /** Gets an immediate successor of this basic block, if any. */
14- BasicBlock getASuccessor ( ) { result .getFirstNode ( ) = this .getLastNode ( ) .getASuccessor ( ) }
15-
16- /** Gets an immediate successor of this basic block of a given type, if any. */
17- BasicBlock getASuccessorByType ( ControlFlow:: SuccessorType t ) {
18- result .getFirstNode ( ) = this .getLastNode ( ) .getASuccessorByType ( t )
19- }
20-
21- /** Gets an immediate predecessor of this basic block, if any. */
22- BasicBlock getAPredecessor ( ) { result .getASuccessor ( ) = this }
10+ final class BasicBlock extends BasicBlockImpl:: BasicBlock {
11+ BasicBlock getASuccessorByType ( ControlFlow:: SuccessorType t ) { result = this .getASuccessor ( t ) }
2312
24- /** Gets an immediate predecessor of this basic block of a given type, if any. */
2513 BasicBlock getAPredecessorByType ( ControlFlow:: SuccessorType t ) {
26- result . getASuccessorByType ( t ) = this
14+ result = this . getAPredecessor ( t )
2715 }
2816
2917 /**
@@ -65,23 +53,20 @@ class BasicBlock extends TBasicBlockStart {
6553 }
6654
6755 /** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
68- ControlFlow:: Node getNode ( int pos ) { bbIndex ( this . getFirstNode ( ) , result , pos ) }
56+ ControlFlow:: Node getNode ( int pos ) { result = super . getNode ( pos ) }
6957
7058 /** Gets a control flow node in this basic block. */
71- ControlFlow:: Node getANode ( ) { result = this . getNode ( _ ) }
59+ ControlFlow:: Node getANode ( ) { result = super . getANode ( ) }
7260
7361 /** Gets the first control flow node in this basic block. */
74- ControlFlow:: Node getFirstNode ( ) { this = TBasicBlockStart ( result ) }
62+ ControlFlow:: Node getFirstNode ( ) { result = super . getFirstNode ( ) }
7563
7664 /** Gets the last control flow node in this basic block. */
77- ControlFlow:: Node getLastNode ( ) { result = this . getNode ( this . length ( ) - 1 ) }
65+ ControlFlow:: Node getLastNode ( ) { result = super . getLastNode ( ) }
7866
7967 /** Gets the callable that this basic block belongs to. */
8068 final Callable getCallable ( ) { result = this .getFirstNode ( ) .getEnclosingCallable ( ) }
8169
82- /** Gets the length of this basic block. */
83- int length ( ) { result = strictcount ( this .getANode ( ) ) }
84-
8570 /**
8671 * Holds if this basic block immediately dominates basic block `bb`.
8772 *
@@ -103,7 +88,7 @@ class BasicBlock extends TBasicBlockStart {
10388 * basic block on line 4 (all paths from the entry point of `M`
10489 * to `return s.Length;` must go through the null check).
10590 */
106- predicate immediatelyDominates ( BasicBlock bb ) { bbIDominates ( this , bb ) }
91+ predicate immediatelyDominates ( BasicBlock bb ) { super . immediatelyDominates ( bb ) }
10792
10893 /**
10994 * Holds if this basic block strictly dominates basic block `bb`.
@@ -126,7 +111,7 @@ class BasicBlock extends TBasicBlockStart {
126111 * basic block on line 4 (all paths from the entry point of `M`
127112 * to `return s.Length;` must go through the null check).
128113 */
129- predicate strictlyDominates ( BasicBlock bb ) { bbIDominates + ( this , bb ) }
114+ predicate strictlyDominates ( BasicBlock bb ) { super . strictlyDominates ( bb ) }
130115
131116 /**
132117 * Holds if this basic block dominates basic block `bb`.
@@ -178,15 +163,7 @@ class BasicBlock extends TBasicBlockStart {
178163 * `Console.Write(x);`. Also, the basic block starting on line 2
179164 * does not dominate the basic block on line 6.
180165 */
181- predicate inDominanceFrontier ( BasicBlock df ) {
182- this .dominatesPredecessor ( df ) and
183- not this .strictlyDominates ( df )
184- }
185-
186- /**
187- * Holds if this basic block dominates a predecessor of `df`.
188- */
189- private predicate dominatesPredecessor ( BasicBlock df ) { this .dominates ( df .getAPredecessor ( ) ) }
166+ predicate inDominanceFrontier ( BasicBlock df ) { super .inDominanceFrontier ( df ) }
190167
191168 /**
192169 * Gets the basic block that immediately dominates this basic block, if any.
@@ -208,7 +185,7 @@ class BasicBlock extends TBasicBlockStart {
208185 * the basic block online 4 (all paths from the entry point of `M`
209186 * to `return s.Length;` must go through the null check.
210187 */
211- BasicBlock getImmediateDominator ( ) { bbIDominates ( result , this ) }
188+ BasicBlock getImmediateDominator ( ) { result = super . getImmediateDominator ( ) }
212189
213190 /**
214191 * Holds if this basic block strictly post-dominates basic block `bb`.
@@ -234,7 +211,7 @@ class BasicBlock extends TBasicBlockStart {
234211 * line 3 (all paths to the exit point of `M` from `return s.Length;`
235212 * must go through the `WriteLine` call).
236213 */
237- predicate strictlyPostDominates ( BasicBlock bb ) { bbIPostDominates + ( this , bb ) }
214+ predicate strictlyPostDominates ( BasicBlock bb ) { super . strictlyPostDominates ( bb ) }
238215
239216 /**
240217 * Holds if this basic block post-dominates basic block `bb`.
@@ -262,10 +239,7 @@ class BasicBlock extends TBasicBlockStart {
262239 * This predicate is *reflexive*, so for example `Console.WriteLine("M");`
263240 * post-dominates itself.
264241 */
265- predicate postDominates ( BasicBlock bb ) {
266- this .strictlyPostDominates ( bb ) or
267- this = bb
268- }
242+ predicate postDominates ( BasicBlock bb ) { super .postDominates ( bb ) }
269243
270244 /**
271245 * Holds if this basic block is in a loop in the control flow graph. This
@@ -274,230 +248,26 @@ class BasicBlock extends TBasicBlockStart {
274248 * necessary back edges are unreachable.
275249 */
276250 predicate inLoop ( ) { this .getASuccessor + ( ) = this }
277-
278- /** Gets a textual representation of this basic block. */
279- string toString ( ) { result = this .getFirstNode ( ) .toString ( ) }
280-
281- /** Gets the location of this basic block. */
282- Location getLocation ( ) { result = this .getFirstNode ( ) .getLocation ( ) }
283- }
284-
285- /**
286- * Internal implementation details.
287- */
288- cached
289- private module Internal {
290- /** Internal representation of basic blocks. */
291- cached
292- newtype TBasicBlock = TBasicBlockStart ( ControlFlow:: Node cfn ) { startsBB ( cfn ) }
293-
294- /** Holds if `cfn` starts a new basic block. */
295- private predicate startsBB ( ControlFlow:: Node cfn ) {
296- not exists ( cfn .getAPredecessor ( ) ) and exists ( cfn .getASuccessor ( ) )
297- or
298- cfn .isJoin ( )
299- or
300- cfn .getAPredecessor ( ) .isBranch ( )
301- or
302- /*
303- * In cases such as
304- * ```csharp
305- * if (b)
306- * M()
307- * ```
308- * where the `false` edge out of `b` is not present (because we can prove it
309- * impossible), we still split up the basic block in two, in order to generate
310- * a `ConditionBlock` which can be used by the guards library.
311- */
312-
313- exists ( cfn .getAPredecessorByType ( any ( ControlFlow:: SuccessorTypes:: ConditionalSuccessor s ) ) )
314- }
315-
316- /**
317- * Holds if `succ` is a control flow successor of `pred` within
318- * the same basic block.
319- */
320- private predicate intraBBSucc ( ControlFlow:: Node pred , ControlFlow:: Node succ ) {
321- succ = pred .getASuccessor ( ) and
322- not startsBB ( succ )
323- }
324-
325- /**
326- * Holds if `cfn` is the `i`th node in basic block `bb`.
327- *
328- * In other words, `i` is the shortest distance from a node `bb`
329- * that starts a basic block to `cfn` along the `intraBBSucc` relation.
330- */
331- cached
332- predicate bbIndex ( ControlFlow:: Node bbStart , ControlFlow:: Node cfn , int i ) =
333- shortestDistances( startsBB / 1 , intraBBSucc / 2 ) ( bbStart , cfn , i )
334-
335- /**
336- * Holds if the first node of basic block `succ` is a control flow
337- * successor of the last node of basic block `pred`.
338- */
339- private predicate succBB ( BasicBlock pred , BasicBlock succ ) { succ = pred .getASuccessor ( ) }
340-
341- /** Holds if `dom` is an immediate dominator of `bb`. */
342- cached
343- predicate bbIDominates ( BasicBlock dom , BasicBlock bb ) =
344- idominance( entryBB / 1 , succBB / 2 ) ( _, dom , bb )
345-
346- /** Holds if `pred` is a basic block predecessor of `succ`. */
347- private predicate predBB ( BasicBlock succ , BasicBlock pred ) { succBB ( pred , succ ) }
348-
349- /** Holds if `bb` is an exit basic block that represents normal exit. */
350- private predicate normalExitBB ( BasicBlock bb ) {
351- bb .getANode ( ) .( ControlFlow:: Nodes:: AnnotatedExitNode ) .isNormal ( )
352- }
353-
354- /** Holds if `dom` is an immediate post-dominator of `bb`. */
355- cached
356- predicate bbIPostDominates ( BasicBlock dom , BasicBlock bb ) =
357- idominance( normalExitBB / 1 , predBB / 2 ) ( _, dom , bb )
358- }
359-
360- private import Internal
361-
362- /**
363- * An entry basic block, that is, a basic block whose first node is
364- * the entry node of a callable.
365- */
366- class EntryBasicBlock extends BasicBlock {
367- EntryBasicBlock ( ) { entryBB ( this ) }
368- }
369-
370- /** Holds if `bb` is an entry basic block. */
371- private predicate entryBB ( BasicBlock bb ) {
372- bb .getFirstNode ( ) instanceof ControlFlow:: Nodes:: EntryNode
373- }
374-
375- /**
376- * An annotated exit basic block, that is, a basic block that contains
377- * an annotated exit node.
378- */
379- class AnnotatedExitBasicBlock extends BasicBlock {
380- private boolean isNormal ;
381-
382- AnnotatedExitBasicBlock ( ) {
383- this .getANode ( ) =
384- any ( ControlFlow:: Nodes:: AnnotatedExitNode n |
385- if n .isNormal ( ) then isNormal = true else isNormal = false
386- )
387- }
388-
389- /** Holds if this block represents a normal exit. */
390- predicate isNormal ( ) { isNormal = true }
391- }
392-
393- /**
394- * An exit basic block, that is, a basic block whose last node is
395- * the exit node of a callable.
396- */
397- class ExitBasicBlock extends BasicBlock {
398- ExitBasicBlock ( ) { this .getLastNode ( ) instanceof ControlFlow:: Nodes:: ExitNode }
399251}
400252
401- private module JoinBlockPredecessors {
402- private import ControlFlow:: Nodes
403- private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as Impl
253+ final class EntryBasicBlock extends BasicBlock , BasicBlockImpl:: EntryBasicBlock { }
404254
405- int getId ( JoinBlockPredecessor jbp ) {
406- exists ( Impl:: AstNode n | result = n .getId ( ) |
407- n = jbp .getFirstNode ( ) .getAstNode ( )
408- or
409- n = jbp .( EntryBasicBlock ) .getCallable ( )
410- )
411- }
255+ final class AnnotatedExitBasicBlock extends BasicBlock , BasicBlockImpl:: AnnotatedExitBasicBlock { }
412256
413- string getSplitString ( JoinBlockPredecessor jbp ) {
414- result = jbp .getFirstNode ( ) .( ElementNode ) .getSplitsString ( )
415- or
416- not exists ( jbp .getFirstNode ( ) .( ElementNode ) .getSplitsString ( ) ) and
417- result = ""
418- }
419- }
420-
421- /** A basic block with more than one predecessor. */
422- class JoinBlock extends BasicBlock {
423- JoinBlock ( ) { this .getFirstNode ( ) .isJoin ( ) }
257+ final class ExitBasicBlock extends BasicBlock , BasicBlockImpl:: ExitBasicBlock { }
424258
425- /**
426- * Gets the `i`th predecessor of this join block, with respect to some
427- * arbitrary order.
428- */
429- cached
430- JoinBlockPredecessor getJoinBlockPredecessor ( int i ) {
431- result =
432- rank [ i + 1 ] ( JoinBlockPredecessor jbp |
433- jbp = this .getAPredecessor ( )
434- |
435- jbp order by JoinBlockPredecessors:: getId ( jbp ) , JoinBlockPredecessors:: getSplitString ( jbp )
436- )
437- }
438- }
439-
440- /** A basic block that is an immediate predecessor of a join block. */
441- class JoinBlockPredecessor extends BasicBlock {
442- JoinBlockPredecessor ( ) { this .getASuccessor ( ) instanceof JoinBlock }
259+ final class JoinBlock extends BasicBlock , BasicBlockImpl:: JoinBasicBlock {
260+ JoinBlockPredecessor getJoinBlockPredecessor ( int i ) { result = super .getJoinBlockPredecessor ( i ) }
443261}
444262
445- /** A basic block that terminates in a condition, splitting the subsequent control flow. */
446- class ConditionBlock extends BasicBlock {
447- ConditionBlock ( ) { this .getLastNode ( ) .isCondition ( ) }
263+ final class JoinBlockPredecessor extends BasicBlock , BasicBlockImpl:: JoinPredecessorBasicBlock { }
448264
449- /**
450- * Holds if basic block `succ` is immediately controlled by this basic
451- * block with conditional value `s`. That is, `succ` is an immediate
452- * successor of this block, and `succ` can only be reached from
453- * the callable entry point by going via the `s` edge out of this basic block.
454- */
455- pragma [ nomagic]
265+ final class ConditionBlock extends BasicBlock , BasicBlockImpl:: ConditionBasicBlock {
456266 predicate immediatelyControls ( BasicBlock succ , ConditionalSuccessor s ) {
457- succ = this .getASuccessorByType ( s ) and
458- forall ( BasicBlock pred | pred = succ .getAPredecessor ( ) and pred != this | succ .dominates ( pred ) )
267+ super .immediatelyControls ( succ , s )
459268 }
460269
461- /**
462- * Holds if basic block `controlled` is controlled by this basic block with
463- * conditional value `s`. That is, `controlled` can only be reached from
464- * the callable entry point by going via the `s` edge out of this basic block.
465- */
466270 predicate controls ( BasicBlock controlled , ConditionalSuccessor s ) {
467- /*
468- * For this block to control the block `controlled` with `testIsTrue` the following must be true:
469- * Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
470- * Execution must have passed through the `testIsTrue` edge leaving `this`.
471- *
472- * Although "passed through the true edge" implies that `this.getATrueSuccessor()` dominates `controlled`,
473- * the reverse is not true, as flow may have passed through another edge to get to `this.getATrueSuccessor()`
474- * so we need to assert that `this.getATrueSuccessor()` dominates `controlled` *and* that
475- * all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`.
476- *
477- * For example, in the following C# snippet:
478- * ```csharp
479- * if (x)
480- * controlled;
481- * false_successor;
482- * uncontrolled;
483- * ```
484- * `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`)
485- * or dominated by itself. Whereas in the following code:
486- * ```csharp
487- * if (x)
488- * while (controlled)
489- * also_controlled;
490- * false_successor;
491- * uncontrolled;
492- * ```
493- * the block `while controlled` is controlled because all of its predecessors are `this` (`if (x)`)
494- * or (in the case of `also_controlled`) dominated by itself.
495- *
496- * The additional constraint on the predecessors of the test successor implies
497- * that `this` strictly dominates `controlled` so that isn't necessary to check
498- * directly.
499- */
500-
501- exists ( BasicBlock succ | this .immediatelyControls ( succ , s ) | succ .dominates ( controlled ) )
271+ super .controls ( controlled , s )
502272 }
503273}
0 commit comments