@@ -13,6 +13,23 @@ private import semmle.code.csharp.controlflow.BasicBlocks
1313private import semmle.code.csharp.controlflow.internal.Completion
1414private import semmle.code.csharp.frameworks.System
1515
16+ /** An expression whose value may control the execution of another element. */
17+ class Guard extends Expr {
18+ Guard ( ) { isGuard ( this , _) }
19+
20+ /**
21+ * Holds if `cfn` is guarded by this expression having value `v`, where `sub` is
22+ * a sub expression of this expression that is structurally equal to the expression
23+ * belonging to `cfn`.
24+ *
25+ * In case `cfn` or `sub` access an SSA variable in their left-most qualifier, then
26+ * so must the other (accessing the same SSA variable).
27+ */
28+ predicate controlsNode ( ControlFlow:: Nodes:: ElementNode cfn , AccessOrCallExpr sub , AbstractValue v ) {
29+ isGuardedByNode ( cfn , this , sub , v )
30+ }
31+ }
32+
1633/** An abstract value. */
1734abstract class AbstractValue extends TAbstractValue {
1835 /** Holds if the `s` branch out of `cfe` is taken iff `e` has this value. */
@@ -481,7 +498,7 @@ class GuardedExpr extends AccessOrCallExpr {
481498 * left-most qualifier, then so must the other (accessing the same SSA
482499 * variable).
483500 */
484- Expr getAGuard ( Expr sub , AbstractValue v ) {
501+ Guard getAGuard ( Expr sub , AbstractValue v ) {
485502 result = g and
486503 sub = sub0 and
487504 v = v0
@@ -492,7 +509,7 @@ class GuardedExpr extends AccessOrCallExpr {
492509 * expression is guarded by a structurally equal expression having abstract
493510 * value `v`.
494511 */
495- predicate mustHaveValue ( AbstractValue v ) { exists ( Expr e | e = this .getAGuard ( e , v ) ) }
512+ predicate mustHaveValue ( AbstractValue v ) { g = this .getAGuard ( g , v ) }
496513
497514 /**
498515 * Holds if this expression is guarded by expression `cond`, which must
@@ -533,7 +550,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
533550
534551 private AbstractValue v0 ;
535552
536- GuardedControlFlowNode ( ) { isGuardedByNode ( this , g , sub0 , v0 ) }
553+ GuardedControlFlowNode ( ) { g . controlsNode ( this , sub0 , v0 ) }
537554
538555 /**
539556 * Gets an expression that guards this control flow node. That is, this control
@@ -546,7 +563,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
546563 * left-most qualifier, then so must the other (accessing the same SSA
547564 * variable).
548565 */
549- Expr getAGuard ( Expr sub , AbstractValue v ) {
566+ Guard getAGuard ( Expr sub , AbstractValue v ) {
550567 result = g and
551568 sub = sub0 and
552569 v = v0
@@ -557,7 +574,7 @@ class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode {
557574 * control flow node is guarded by a structurally equal expression having
558575 * abstract value `v`.
559576 */
560- predicate mustHaveValue ( AbstractValue v ) { exists ( Expr e | e = this .getAGuard ( e , v ) ) }
577+ predicate mustHaveValue ( AbstractValue v ) { g = this .getAGuard ( g , v ) }
561578}
562579
563580/**
@@ -587,7 +604,7 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
587604
588605 GuardedDataFlowNode ( ) {
589606 exists ( ControlFlow:: Nodes:: ElementNode cfn | exists ( this .getExprAtNode ( cfn ) ) |
590- isGuardedByNode ( cfn , g , sub0 , v0 )
607+ g . controlsNode ( cfn , sub0 , v0 )
591608 )
592609 }
593610
@@ -602,7 +619,7 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
602619 * left-most qualifier, then so must the other (accessing the same SSA
603620 * variable).
604621 */
605- Expr getAGuard ( Expr sub , AbstractValue v ) {
622+ Guard getAGuard ( Expr sub , AbstractValue v ) {
606623 result = g and
607624 sub = sub0 and
608625 v = v0
@@ -613,7 +630,7 @@ class GuardedDataFlowNode extends DataFlow::ExprNode {
613630 * data flow node is guarded by a structurally equal expression having
614631 * abstract value `v`.
615632 */
616- predicate mustHaveValue ( AbstractValue v ) { exists ( Expr e | e = this .getAGuard ( e , v ) ) }
633+ predicate mustHaveValue ( AbstractValue v ) { g = this .getAGuard ( g , v ) }
617634}
618635
619636/** An expression guarded by a `null` check. */
@@ -761,72 +778,49 @@ module Internal {
761778 e = any ( BinaryArithmeticOperation bao | result = bao .getAnOperand ( ) )
762779 }
763780
764- /** An expression whose value may control the execution of another element. */
765- class Guard extends Expr {
766- private AbstractValue val ;
781+ /** Holds if basic block `bb` only is reached when guard `g` has abstract value `v`. */
782+ private predicate guardControls ( Guard g , BasicBlock bb , AbstractValue v ) {
783+ exists ( ControlFlowElement cfe , ConditionalSuccessor s , AbstractValue v0 , Guard g0 |
784+ cfe .controlsBlock ( bb , s )
785+ |
786+ v0 .branch ( cfe , s , g0 ) and
787+ impliesSteps ( g0 , v0 , g , v )
788+ )
789+ }
767790
768- Guard ( ) {
769- this .getType ( ) instanceof BoolType and
770- not this instanceof BoolLiteral and
771- not this instanceof SwitchCaseExpr and
772- not this instanceof PatternExpr and
773- val = TBooleanValue ( _)
774- or
775- this instanceof DereferenceableExpr and
776- val = TNullValue ( _)
777- or
778- val .branch ( _, _, this )
791+ /**
792+ * Holds if control flow node `cfn` only is reached when guard `g` evaluates to `v`,
793+ * because of an assertion.
794+ */
795+ private predicate guardAssertionControlsNode ( Guard g , ControlFlow:: Node cfn , AbstractValue v ) {
796+ exists ( Assertion a , Guard g0 , AbstractValue v0 |
797+ asserts ( a , g0 , v0 ) and
798+ impliesSteps ( g0 , v0 , g , v )
799+ |
800+ a .strictlyDominates ( cfn .getBasicBlock ( ) )
779801 or
780- asserts ( _, this , val )
781- }
782-
783- /** Gets an abstract value that this guard may have. */
784- AbstractValue getAValue ( ) { result = val }
785-
786- /** Holds if basic block `bb` only is reached when this guard has abstract value `v`. */
787- predicate controls ( BasicBlock bb , AbstractValue v ) {
788- exists ( ControlFlowElement cfe , ConditionalSuccessor s , AbstractValue v0 , Guard g |
789- cfe .controlsBlock ( bb , s )
790- |
791- v0 .branch ( cfe , s , g ) and
792- impliesSteps ( g , v0 , this , v )
793- )
794- }
795-
796- /**
797- * Holds if control flow node `cfn` only is reached when this guard evaluates to `v`,
798- * because of an assertion.
799- */
800- predicate assertionControlsNode ( ControlFlow:: Node cfn , AbstractValue v ) {
801- exists ( Assertion a , Guard g , AbstractValue v0 |
802- asserts ( a , g , v0 ) and
803- impliesSteps ( g , v0 , this , v )
804- |
805- a .strictlyDominates ( cfn .getBasicBlock ( ) )
806- or
807- exists ( BasicBlock bb , int i , int j | bb .getNode ( i ) = a .getAControlFlowNode ( ) |
808- bb .getNode ( j ) = cfn and
809- j > i
810- )
802+ exists ( BasicBlock bb , int i , int j | bb .getNode ( i ) = a .getAControlFlowNode ( ) |
803+ bb .getNode ( j ) = cfn and
804+ j > i
811805 )
812- }
806+ )
807+ }
813808
814- /**
815- * Holds if control flow element `cfe` only is reached when this guard evaluates to `v`,
816- * because of an assertion.
817- */
818- predicate assertionControlsElement ( ControlFlowElement cfe , AbstractValue v ) {
819- forex ( ControlFlow:: Node cfn | cfn = cfe .getAControlFlowNode ( ) |
820- this . assertionControlsNode ( cfn , v )
821- )
822- }
809+ /**
810+ * Holds if control flow element `cfe` only is reached when guard `g` evaluates to `v`,
811+ * because of an assertion.
812+ */
813+ private predicate guardAssertionControlsElement ( Guard g , ControlFlowElement cfe , AbstractValue v ) {
814+ forex ( ControlFlow:: Node cfn | cfn = cfe .getAControlFlowNode ( ) |
815+ guardAssertionControlsNode ( g , cfn , v )
816+ )
817+ }
823818
824- /** Same as `this.getAChildExpr*()`, but avoids `fastTC`. */
825- Expr getAChildExprStar ( ) {
826- result = this
827- or
828- result = this .getAChildExprStar ( ) .getAChildExpr ( )
829- }
819+ /** Same as `this.getAChildExpr*()`, but avoids `fastTC`. */
820+ private Expr getAChildExprStar ( Guard g ) {
821+ result = g
822+ or
823+ result = getAChildExprStar ( g ) .getAChildExpr ( )
830824 }
831825
832826 /**
@@ -1273,8 +1267,24 @@ module Internal {
12731267 private import semmle.code.csharp.Caching
12741268
12751269 cached
1276- predicate isCustomNullCheck ( Call call , Expr arg , BooleanValue v , boolean isNull ) {
1270+ predicate isGuard ( Expr e , AbstractValue val ) {
12771271 Stages:: ControlFlowStage:: forceCachingInSameStage ( ) and
1272+ e .getType ( ) instanceof BoolType and
1273+ not e instanceof BoolLiteral and
1274+ not e instanceof SwitchCaseExpr and
1275+ not e instanceof PatternExpr and
1276+ val = TBooleanValue ( _)
1277+ or
1278+ e instanceof DereferenceableExpr and
1279+ val = TNullValue ( _)
1280+ or
1281+ val .branch ( _, _, e )
1282+ or
1283+ asserts ( _, e , val )
1284+ }
1285+
1286+ cached
1287+ predicate isCustomNullCheck ( Call call , Expr arg , BooleanValue v , boolean isNull ) {
12781288 exists ( Callable callable , Parameter p |
12791289 arg = call .getArgumentForParameter ( any ( Parameter p0 | p0 .getSourceDeclaration ( ) = p ) ) and
12801290 call .getTarget ( ) .getSourceDeclaration ( ) = callable and
@@ -1355,7 +1365,7 @@ module Internal {
13551365 )
13561366 )
13571367 or
1358- v1 = g1 . getAValue ( ) and
1368+ isGuard ( g1 , v1 ) and
13591369 v1 = any ( MatchValue mv |
13601370 mv .isMatch ( ) and
13611371 g2 = g1 and
@@ -1379,20 +1389,20 @@ module Internal {
13791389 v2 = v1
13801390 or
13811391 g2 = g1 .( AssignExpr ) .getRValue ( ) and
1382- v1 = g1 . getAValue ( ) and
1392+ isGuard ( g1 , v1 ) and
13831393 v2 = v1
13841394 or
13851395 g2 = g1 .( Assignment ) .getLValue ( ) and
1386- v1 = g1 . getAValue ( ) and
1396+ isGuard ( g1 , v1 ) and
13871397 v2 = v1
13881398 or
13891399 g2 = g1 .( CastExpr ) .getExpr ( ) and
1390- v1 = g1 . getAValue ( ) and
1400+ isGuard ( g1 , v1 ) and
13911401 v2 = v1 .( NullValue )
13921402 or
13931403 exists ( PreSsa:: Definition def | def .getDefinition ( ) .getSource ( ) = g2 |
13941404 g1 = def .getARead ( ) and
1395- v1 = g1 . getAValue ( ) and
1405+ isGuard ( g1 , v1 ) and
13961406 v2 = v1
13971407 )
13981408 or
@@ -1473,10 +1483,10 @@ module Internal {
14731483 pragma [ noinline]
14741484 private predicate candidateAux ( AccessOrCallExpr e , Declaration target , BasicBlock bb ) {
14751485 target = e .getTarget ( ) and
1476- exists ( Guard g | e = g . getAChildExprStar ( ) |
1477- g . controls ( bb , _)
1486+ exists ( Guard g | e = getAChildExprStar ( g ) |
1487+ guardControls ( g , bb , _)
14781488 or
1479- g . assertionControlsNode ( bb .getANode ( ) , _)
1489+ guardAssertionControlsNode ( g , bb .getANode ( ) , _)
14801490 )
14811491 }
14821492 }
@@ -1492,7 +1502,7 @@ module Internal {
14921502 ) {
14931503 Stages:: GuardsStage:: forceCachingInSameStage ( ) and
14941504 cfn = guarded .getAControlFlowNode ( ) and
1495- g . controls ( cfn .getBasicBlock ( ) , v ) and
1505+ guardControls ( g , cfn .getBasicBlock ( ) , v ) and
14961506 exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded ) )
14971507 }
14981508
@@ -1504,7 +1514,7 @@ module Internal {
15041514 isGuardedByNode0 ( cfn , guarded , g , sub , v )
15051515 )
15061516 or
1507- g . assertionControlsElement ( guarded , v ) and
1517+ guardAssertionControlsElement ( g , guarded , v ) and
15081518 exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded ) )
15091519 }
15101520
@@ -1513,7 +1523,7 @@ module Internal {
15131523 AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v
15141524 ) {
15151525 isGuardedByExpr1 ( guarded , g , sub , v ) and
1516- sub = g . getAChildExprStar ( ) and
1526+ sub = getAChildExprStar ( g ) and
15171527 forall ( Ssa:: Definition def | def = sub .getAnSsaQualifier ( _) |
15181528 def = guarded .getAnSsaQualifier ( _)
15191529 )
@@ -1525,7 +1535,7 @@ module Internal {
15251535 ) {
15261536 isGuardedByNode0 ( guarded , _, g , sub , v )
15271537 or
1528- g . assertionControlsNode ( guarded , v ) and
1538+ guardAssertionControlsNode ( g , guarded , v ) and
15291539 exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded .getElement ( ) ) )
15301540 }
15311541
@@ -1542,7 +1552,7 @@ module Internal {
15421552 ControlFlow:: Nodes:: ElementNode guarded , Guard g , AccessOrCallExpr sub , AbstractValue v
15431553 ) {
15441554 isGuardedByNode1 ( guarded , g , sub , v ) and
1545- sub = g . getAChildExprStar ( ) and
1555+ sub = getAChildExprStar ( g ) and
15461556 forall ( Ssa:: Definition def | def = sub .getAnSsaQualifier ( _) | isGuardedByNode2 ( guarded , def ) )
15471557 }
15481558
@@ -1560,7 +1570,7 @@ module Internal {
15601570 forex ( ControlFlow:: Node cfn | cfn = g1 .getAControlFlowNode ( ) |
15611571 exists ( Ssa:: ExplicitDefinition def | def .getADefinition ( ) .getSource ( ) = g2 |
15621572 g1 = def .getAReadAtNode ( cfn ) and
1563- v1 = g1 . getAValue ( ) and
1573+ isGuard ( g1 , v1 ) and
15641574 v2 = v1
15651575 )
15661576 )
@@ -1578,7 +1588,7 @@ module Internal {
15781588 predicate preImpliesSteps ( Guard g1 , AbstractValue v1 , Guard g2 , AbstractValue v2 ) {
15791589 g1 = g2 and
15801590 v1 = v2 and
1581- v1 = g1 . getAValue ( )
1591+ isGuard ( g1 , v1 )
15821592 or
15831593 exists ( Expr mid , AbstractValue vMid | preImpliesSteps ( g1 , v1 , mid , vMid ) |
15841594 preImpliesStep ( mid , vMid , g2 , v2 )
@@ -1595,7 +1605,7 @@ module Internal {
15951605 predicate impliesSteps ( Guard g1 , AbstractValue v1 , Guard g2 , AbstractValue v2 ) {
15961606 g1 = g2 and
15971607 v1 = v2 and
1598- v1 = g1 . getAValue ( )
1608+ isGuard ( g1 , v1 )
15991609 or
16001610 exists ( Expr mid , AbstractValue vMid | impliesSteps ( g1 , v1 , mid , vMid ) |
16011611 impliesStep ( mid , vMid , g2 , v2 )
0 commit comments