4
4
5
5
import csharp
6
6
private import ControlFlow:: SuccessorTypes
7
+ private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as CfgImpl
8
+ private import CfgImpl:: BasicBlocks as BasicBlocksImpl
7
9
8
10
/**
9
11
* A basic block, that is, a maximal straight-line sequence of control flow nodes
10
12
* without branches or joins.
11
13
*/
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
-
14
+ final class BasicBlock extends BasicBlocksImpl:: BasicBlock {
16
15
/** 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 }
16
+ BasicBlock getASuccessorByType ( ControlFlow:: SuccessorType t ) { result = this .getASuccessor ( t ) }
23
17
24
18
/** Gets an immediate predecessor of this basic block of a given type, if any. */
25
19
BasicBlock getAPredecessorByType ( ControlFlow:: SuccessorType t ) {
26
- result . getASuccessorByType ( t ) = this
20
+ result = this . getAPredecessor ( t )
27
21
}
28
22
29
23
/**
@@ -65,23 +59,20 @@ class BasicBlock extends TBasicBlockStart {
65
59
}
66
60
67
61
/** 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 ) }
62
+ ControlFlow:: Node getNode ( int pos ) { result = super . getNode ( pos ) }
69
63
70
64
/** Gets a control flow node in this basic block. */
71
- ControlFlow:: Node getANode ( ) { result = this . getNode ( _ ) }
65
+ ControlFlow:: Node getANode ( ) { result = super . getANode ( ) }
72
66
73
67
/** Gets the first control flow node in this basic block. */
74
- ControlFlow:: Node getFirstNode ( ) { this = TBasicBlockStart ( result ) }
68
+ ControlFlow:: Node getFirstNode ( ) { result = super . getFirstNode ( ) }
75
69
76
70
/** Gets the last control flow node in this basic block. */
77
- ControlFlow:: Node getLastNode ( ) { result = this . getNode ( this . length ( ) - 1 ) }
71
+ ControlFlow:: Node getLastNode ( ) { result = super . getLastNode ( ) }
78
72
79
73
/** Gets the callable that this basic block belongs to. */
80
74
final Callable getCallable ( ) { result = this .getFirstNode ( ) .getEnclosingCallable ( ) }
81
75
82
- /** Gets the length of this basic block. */
83
- int length ( ) { result = strictcount ( this .getANode ( ) ) }
84
-
85
76
/**
86
77
* Holds if this basic block immediately dominates basic block `bb`.
87
78
*
@@ -103,7 +94,7 @@ class BasicBlock extends TBasicBlockStart {
103
94
* basic block on line 4 (all paths from the entry point of `M`
104
95
* to `return s.Length;` must go through the null check).
105
96
*/
106
- predicate immediatelyDominates ( BasicBlock bb ) { bbIDominates ( this , bb ) }
97
+ predicate immediatelyDominates ( BasicBlock bb ) { super . immediatelyDominates ( bb ) }
107
98
108
99
/**
109
100
* Holds if this basic block strictly dominates basic block `bb`.
@@ -126,7 +117,7 @@ class BasicBlock extends TBasicBlockStart {
126
117
* basic block on line 4 (all paths from the entry point of `M`
127
118
* to `return s.Length;` must go through the null check).
128
119
*/
129
- predicate strictlyDominates ( BasicBlock bb ) { bbIDominates + ( this , bb ) }
120
+ predicate strictlyDominates ( BasicBlock bb ) { super . strictlyDominates ( bb ) }
130
121
131
122
/**
132
123
* Holds if this basic block dominates basic block `bb`.
@@ -178,15 +169,7 @@ class BasicBlock extends TBasicBlockStart {
178
169
* `Console.Write(x);`. Also, the basic block starting on line 2
179
170
* does not dominate the basic block on line 6.
180
171
*/
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 ( ) ) }
172
+ predicate inDominanceFrontier ( BasicBlock df ) { super .inDominanceFrontier ( df ) }
190
173
191
174
/**
192
175
* Gets the basic block that immediately dominates this basic block, if any.
@@ -208,7 +191,7 @@ class BasicBlock extends TBasicBlockStart {
208
191
* the basic block online 4 (all paths from the entry point of `M`
209
192
* to `return s.Length;` must go through the null check.
210
193
*/
211
- BasicBlock getImmediateDominator ( ) { bbIDominates ( result , this ) }
194
+ BasicBlock getImmediateDominator ( ) { result = super . getImmediateDominator ( ) }
212
195
213
196
/**
214
197
* Holds if this basic block strictly post-dominates basic block `bb`.
@@ -234,7 +217,7 @@ class BasicBlock extends TBasicBlockStart {
234
217
* line 3 (all paths to the exit point of `M` from `return s.Length;`
235
218
* must go through the `WriteLine` call).
236
219
*/
237
- predicate strictlyPostDominates ( BasicBlock bb ) { bbIPostDominates + ( this , bb ) }
220
+ predicate strictlyPostDominates ( BasicBlock bb ) { super . strictlyPostDominates ( bb ) }
238
221
239
222
/**
240
223
* Holds if this basic block post-dominates basic block `bb`.
@@ -262,10 +245,7 @@ class BasicBlock extends TBasicBlockStart {
262
245
* This predicate is *reflexive*, so for example `Console.WriteLine("M");`
263
246
* post-dominates itself.
264
247
*/
265
- predicate postDominates ( BasicBlock bb ) {
266
- this .strictlyPostDominates ( bb ) or
267
- this = bb
268
- }
248
+ predicate postDominates ( BasicBlock bb ) { super .postDominates ( bb ) }
269
249
270
250
/**
271
251
* Holds if this basic block is in a loop in the control flow graph. This
@@ -274,230 +254,44 @@ class BasicBlock extends TBasicBlockStart {
274
254
* necessary back edges are unreachable.
275
255
*/
276
256
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
257
}
359
258
360
- private import Internal
361
-
362
259
/**
363
260
* An entry basic block, that is, a basic block whose first node is
364
- * the entry node of a callable .
261
+ * an entry node.
365
262
*/
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
- }
263
+ final class EntryBasicBlock extends BasicBlock , BasicBlocksImpl:: EntryBasicBlock { }
374
264
375
265
/**
376
- * An annotated exit basic block, that is, a basic block that contains
377
- * an annotated exit node.
266
+ * An annotated exit basic block, that is, a basic block that contains an
267
+ * annotated exit node.
378
268
*/
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
- }
269
+ final class AnnotatedExitBasicBlock extends BasicBlock , BasicBlocksImpl:: AnnotatedExitBasicBlock { }
392
270
393
271
/**
394
272
* An exit basic block, that is, a basic block whose last node is
395
- * the exit node of a callable .
273
+ * an exit node.
396
274
*/
397
- class ExitBasicBlock extends BasicBlock {
398
- ExitBasicBlock ( ) { this .getLastNode ( ) instanceof ControlFlow:: Nodes:: ExitNode }
399
- }
400
-
401
- private module JoinBlockPredecessors {
402
- private import ControlFlow:: Nodes
403
- private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as Impl
404
-
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
- }
412
-
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
- }
275
+ final class ExitBasicBlock extends BasicBlock , BasicBlocksImpl:: ExitBasicBlock { }
420
276
421
277
/** A basic block with more than one predecessor. */
422
- class JoinBlock extends BasicBlock {
423
- JoinBlock ( ) { this .getFirstNode ( ) .isJoin ( ) }
424
-
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
- }
278
+ final class JoinBlock extends BasicBlock , BasicBlocksImpl:: JoinBasicBlock {
279
+ JoinBlockPredecessor getJoinBlockPredecessor ( int i ) { result = super .getJoinBlockPredecessor ( i ) }
438
280
}
439
281
440
282
/** A basic block that is an immediate predecessor of a join block. */
441
- class JoinBlockPredecessor extends BasicBlock {
442
- JoinBlockPredecessor ( ) { this .getASuccessor ( ) instanceof JoinBlock }
443
- }
444
-
445
- /** A basic block that terminates in a condition, splitting the subsequent control flow. */
446
- class ConditionBlock extends BasicBlock {
447
- ConditionBlock ( ) { this .getLastNode ( ) .isCondition ( ) }
283
+ final class JoinBlockPredecessor extends BasicBlock , BasicBlocksImpl:: JoinPredecessorBasicBlock { }
448
284
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]
285
+ /**
286
+ * A basic block that terminates in a condition, splitting the subsequent
287
+ * control flow.
288
+ */
289
+ final class ConditionBlock extends BasicBlock , BasicBlocksImpl:: ConditionBasicBlock {
456
290
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 ) )
291
+ super .immediatelyControls ( succ , s )
459
292
}
460
293
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
- */
466
294
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 ) )
295
+ super .controls ( controlled , s )
502
296
}
503
297
}
0 commit comments