@@ -417,26 +417,30 @@ class AccessOrCallExpr extends Expr {
417417 * An expression can have more than one SSA qualifier in the presence
418418 * of control flow splitting.
419419 */
420- Ssa:: Definition getAnSsaQualifier ( ) { result = getAnSsaQualifier ( this ) }
420+ Ssa:: Definition getAnSsaQualifier ( ControlFlow:: Node cfn ) {
421+ result = getAnSsaQualifier ( this , cfn )
422+ }
421423}
422424
423425private Declaration getDeclarationTarget ( Expr e ) {
424426 e = any ( AssignableAccess aa | result = aa .getTarget ( ) ) or
425427 result = e .( Call ) .getTarget ( )
426428}
427429
428- private Ssa:: Definition getAnSsaQualifier ( Expr e ) {
429- e = getATrackedAccess ( result )
430+ private Ssa:: Definition getAnSsaQualifier ( Expr e , ControlFlow :: Node cfn ) {
431+ e = getATrackedAccess ( result , cfn )
430432 or
431- not e = getATrackedAccess ( _) and
432- result = getAnSsaQualifier ( e .( QualifiableExpr ) .getQualifier ( ) )
433+ not e = getATrackedAccess ( _, _ ) and
434+ result = getAnSsaQualifier ( e .( QualifiableExpr ) .getQualifier ( ) , cfn )
433435}
434436
435- private AssignableAccess getATrackedAccess ( Ssa:: Definition def ) {
437+ private AssignableAccess getATrackedAccess ( Ssa:: Definition def , ControlFlow :: Node cfn ) {
436438 (
437- result = def .getARead ( )
439+ result = def .getAReadAtNode ( cfn )
438440 or
439- result = def .( Ssa:: ExplicitDefinition ) .getADefinition ( ) .getTargetAccess ( )
441+ result = def .( Ssa:: ExplicitDefinition ) .getADefinition ( ) .getTargetAccess ( ) and
442+ result .getAControlFlowNode ( ) = cfn and
443+ cfn .getBasicBlock ( ) = def .getBasicBlock ( )
440444 ) and
441445 not def instanceof Ssa:: ImplicitUntrackedDefinition
442446}
@@ -483,7 +487,7 @@ class GuardedExpr extends AccessOrCallExpr {
483487 private AccessOrCallExpr sub0 ;
484488 private AbstractValue v0 ;
485489
486- GuardedExpr ( ) { isGuardedBy ( this , g , sub0 , v0 ) }
490+ GuardedExpr ( ) { isGuardedByExpr ( this , g , sub0 , v0 ) }
487491
488492 /**
489493 * Gets an expression that guards this expression. That is, this expression is
@@ -525,13 +529,129 @@ class GuardedExpr extends AccessOrCallExpr {
525529 }
526530}
527531
532+ /**
533+ * A guarded control flow node. A guarded control flow node is like a guarded
534+ * expression (`GuardedExpr`), except control flow graph splitting is taken
535+ * into account. That is, one control flow node belonging to an expression may
536+ * be guarded, while another split need not be guarded:
537+ *
538+ * ```
539+ * if (b)
540+ * if (x == null)
541+ * return;
542+ * x.ToString();
543+ * if (b)
544+ * ...
545+ * ```
546+ *
547+ * In the example above, the node for `x.ToString()` is null-guarded in the
548+ * split `b == true`, but not in the split `b == false`.
549+ */
550+ class GuardedControlFlowNode extends ControlFlow:: Nodes:: ElementNode {
551+ private Guard g ;
552+ private AccessOrCallExpr sub0 ;
553+ private AbstractValue v0 ;
554+
555+ GuardedControlFlowNode ( ) { isGuardedByNode ( this , g , sub0 , v0 ) }
556+
557+ /**
558+ * Gets an expression that guards this control flow node. That is, this control
559+ * flow node is only reached when the returned expression has abstract value `v`.
560+ *
561+ * The expression `sub` is a sub expression of the guarding expression that is
562+ * structurally equal to the expression belonging to this control flow node.
563+ *
564+ * In case this control flow node or `sub` accesses an SSA variable in its
565+ * left-most qualifier, then so must the other (accessing the same SSA
566+ * variable).
567+ */
568+ Expr getAGuard ( Expr sub , AbstractValue v ) {
569+ result = g and
570+ sub = sub0 and
571+ v = v0
572+ }
573+
574+ /**
575+ * Holds if this control flow node must have abstract value `v`. That is, this
576+ * control flow node is guarded by a structurally equal expression having
577+ * abstract value `v`.
578+ */
579+ predicate mustHaveValue ( AbstractValue v ) {
580+ exists ( Expr e | e = this .getAGuard ( e , v ) )
581+ }
582+ }
583+
584+ /**
585+ * A guarded data flow node. A guarded data flow node is like a guarded expression
586+ * (`GuardedExpr`), except control flow graph splitting is taken into account. That
587+ * is, one data flow node belonging to an expression may be guarded, while another
588+ * split need not be guarded:
589+ *
590+ * ```
591+ * if (b)
592+ * if (x == null)
593+ * return;
594+ * x.ToString();
595+ * if (b)
596+ * ...
597+ * ```
598+ *
599+ * In the example above, the node for `x.ToString()` is null-guarded in the
600+ * split `b == true`, but not in the split `b == false`.
601+ */
602+ class GuardedDataFlowNode extends DataFlow:: ExprNode {
603+ private Guard g ;
604+ private AccessOrCallExpr sub0 ;
605+ private AbstractValue v0 ;
606+
607+ GuardedDataFlowNode ( ) {
608+ exists ( ControlFlow:: Nodes:: ElementNode cfn |
609+ exists ( this .getExprAtNode ( cfn ) ) |
610+ isGuardedByNode ( cfn , g , sub0 , v0 )
611+ )
612+ }
613+
614+ /**
615+ * Gets an expression that guards this data flow node. That is, this data flow
616+ * node is only reached when the returned expression has abstract value `v`.
617+ *
618+ * The expression `sub` is a sub expression of the guarding expression that is
619+ * structurally equal to the expression belonging to this data flow node.
620+ *
621+ * In case this data flow node or `sub` accesses an SSA variable in its
622+ * left-most qualifier, then so must the other (accessing the same SSA
623+ * variable).
624+ */
625+ Expr getAGuard ( Expr sub , AbstractValue v ) {
626+ result = g and
627+ sub = sub0 and
628+ v = v0
629+ }
630+
631+ /**
632+ * Holds if this data flow node must have abstract value `v`. That is, this
633+ * data flow node is guarded by a structurally equal expression having
634+ * abstract value `v`.
635+ */
636+ predicate mustHaveValue ( AbstractValue v ) {
637+ exists ( Expr e | e = this .getAGuard ( e , v ) )
638+ }
639+ }
640+
528641/** An expression guarded by a `null` check. */
529642class NullGuardedExpr extends GuardedExpr {
530643 NullGuardedExpr ( ) {
531644 this .mustHaveValue ( any ( NullValue v | not v .isNull ( ) ) )
532645 }
533646}
534647
648+ /** A data flow node guarded by a `null` check. */
649+ class NullGuardedDataFlowNode extends GuardedDataFlowNode {
650+ NullGuardedDataFlowNode ( ) {
651+ this .mustHaveValue ( any ( NullValue v | not v .isNull ( ) ) )
652+ }
653+ }
654+
535655/** INTERNAL: Do not use. */
536656module Internal {
537657 private import ControlFlow:: Internal
@@ -653,7 +773,7 @@ module Internal {
653773 * Holds if control flow node `cfn` only is reached when this guard evaluates to `v`,
654774 * because of an assertion.
655775 */
656- private predicate assertionControlsNode ( ControlFlow:: Node cfn , AbstractValue v ) {
776+ predicate assertionControlsNode ( ControlFlow:: Node cfn , AbstractValue v ) {
657777 exists ( Assertion a , Guard g , AbstractValue v0 |
658778 asserts ( a , g , v0 ) and
659779 impliesSteps ( g , v0 , this , v )
@@ -1097,30 +1217,51 @@ module Internal {
10971217
10981218 private cached module Cached {
10991219 pragma [ noinline]
1100- private predicate isGuardedBy0 ( ControlFlow:: Node cfn , AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1220+ private predicate isGuardedByNode0 ( ControlFlow:: Node cfn , AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
11011221 cfn = guarded .getAControlFlowNode ( ) and
11021222 g .controls ( cfn .getBasicBlock ( ) , v ) and
11031223 exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded ) )
11041224 }
11051225
11061226 pragma [ noinline]
1107- private predicate isGuardedBy1 ( AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1227+ private predicate isGuardedByExpr1 ( AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
11081228 forex ( ControlFlow:: Node cfn |
11091229 cfn = guarded .getAControlFlowNode ( ) |
1110- isGuardedBy0 ( cfn , guarded , g , sub , v )
1230+ isGuardedByNode0 ( cfn , guarded , g , sub , v )
11111231 )
11121232 or
11131233 g .assertionControlsElement ( guarded , v ) and
11141234 exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded ) )
11151235 }
11161236
11171237 cached
1118- predicate isGuardedBy ( AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1119- isGuardedBy1 ( guarded , g , sub , v ) and
1238+ predicate isGuardedByExpr ( AccessOrCallExpr guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1239+ isGuardedByExpr1 ( guarded , g , sub , v ) and
1240+ sub = g .getAChildExpr * ( ) and
1241+ forall ( Ssa:: Definition def |
1242+ def = sub .getAnSsaQualifier ( _) |
1243+ def = guarded .getAnSsaQualifier ( _)
1244+ )
1245+ }
1246+
1247+ pragma [ noinline]
1248+ private predicate isGuardedByNode1 ( ControlFlow:: Nodes:: ElementNode guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1249+ isGuardedByNode0 ( guarded , _, g , sub , v )
1250+ or
1251+ g .assertionControlsNode ( guarded , v ) and
1252+ exists ( ConditionOnExprComparisonConfig c | c .same ( sub , guarded .getElement ( ) ) )
1253+ }
1254+
1255+ cached
1256+ predicate isGuardedByNode ( ControlFlow:: Nodes:: ElementNode guarded , Guard g , AccessOrCallExpr sub , AbstractValue v ) {
1257+ isGuardedByNode1 ( guarded , g , sub , v ) and
11201258 sub = g .getAChildExpr * ( ) and
11211259 forall ( Ssa:: Definition def |
1122- def = sub .getAnSsaQualifier ( ) |
1123- def = guarded .getAnSsaQualifier ( )
1260+ def = sub .getAnSsaQualifier ( _) |
1261+ exists ( ControlFlow:: Node cfn |
1262+ def = guarded .getElement ( ) .( AccessOrCallExpr ) .getAnSsaQualifier ( cfn ) |
1263+ cfn .getBasicBlock ( ) = guarded .getBasicBlock ( )
1264+ )
11241265 )
11251266 }
11261267
0 commit comments