@@ -485,6 +485,17 @@ module Make<LocationSig Location, InputSig<Location> Input> {
485
485
default predicate additionalNullCheck ( PreGuard guard , GuardValue val , Expr e , boolean isNull ) {
486
486
none ( )
487
487
}
488
+
489
+ /**
490
+ * Holds if the assumption that `g1` has been evaluated to `v1` implies that
491
+ * `g2` has been evaluated to `v2`, that is, the evaluation of `g2` to `v2`
492
+ * dominates the evaluation of `g1` to `v1`.
493
+ *
494
+ * This predicate can be instantiated with `CustomGuard<..>::additionalImpliesStep`.
495
+ */
496
+ default predicate additionalImpliesStep ( PreGuard g1 , GuardValue v1 , PreGuard g2 , GuardValue v2 ) {
497
+ none ( )
498
+ }
488
499
}
489
500
490
501
module Logic< LogicInputSig LogicInput> {
@@ -695,41 +706,177 @@ module Make<LocationSig Location, InputSig<Location> Input> {
695
706
)
696
707
}
697
708
698
- pragma [ nomagic]
709
+ private signature predicate baseGuardValueSig ( Guard guard , GuardValue v ) ;
710
+
711
+ /**
712
+ * Calculates the transitive closure of all the guard implication steps
713
+ * starting from a given set of base cases.
714
+ */
715
+ private module ImpliesTC< baseGuardValueSig / 2 baseGuardValue> {
716
+ pragma [ nomagic]
717
+ predicate guardControls ( Guard guard , GuardValue v , Guard tgtGuard , GuardValue tgtVal ) {
718
+ baseGuardValue ( tgtGuard , tgtVal ) and
719
+ guard = tgtGuard and
720
+ v = tgtVal
721
+ or
722
+ exists ( Guard g0 , GuardValue v0 |
723
+ guardControls ( g0 , v0 , tgtGuard , tgtVal ) and
724
+ impliesStep ( g0 , v0 , guard , v )
725
+ )
726
+ or
727
+ exists ( Guard g0 , GuardValue v0 |
728
+ guardControls ( g0 , v0 , tgtGuard , tgtVal ) and
729
+ unboundImpliesStep ( g0 , v0 , guard , v )
730
+ )
731
+ or
732
+ exists ( SsaDefinition def0 , GuardValue v0 |
733
+ ssaControls ( def0 , v0 , tgtGuard , tgtVal ) and
734
+ impliesStepSsaGuard ( def0 , v0 , guard , v )
735
+ )
736
+ or
737
+ exists ( Guard g0 , GuardValue v0 |
738
+ guardControls ( g0 , v0 , tgtGuard , tgtVal ) and
739
+ additionalImpliesStep ( g0 , v0 , guard , v )
740
+ )
741
+ }
742
+
743
+ pragma [ nomagic]
744
+ predicate ssaControls ( SsaDefinition def , GuardValue v , Guard tgtGuard , GuardValue tgtVal ) {
745
+ exists ( Guard g0 |
746
+ guardControls ( g0 , v , tgtGuard , tgtVal ) and
747
+ guardReadsSsaVar ( g0 , def )
748
+ )
749
+ or
750
+ exists ( SsaDefinition def0 |
751
+ ssaControls ( def0 , v , tgtGuard , tgtVal ) and
752
+ impliesStepSsa ( def0 , v , def )
753
+ )
754
+ }
755
+ }
756
+
757
+ private predicate hasAValueBranchEdge ( Guard guard , GuardValue v ) {
758
+ guard .hasValueBranchEdge ( _, _, v )
759
+ }
760
+
761
+ private module BranchImplies = ImpliesTC< hasAValueBranchEdge / 2 > ;
762
+
699
763
private predicate guardControlsBranchEdge (
700
764
Guard guard , BasicBlock bb1 , BasicBlock bb2 , GuardValue v
701
765
) {
702
- guard .hasValueBranchEdge ( bb1 , bb2 , v )
703
- or
704
766
exists ( Guard g0 , GuardValue v0 |
705
- guardControlsBranchEdge ( g0 , bb1 , bb2 , v0 ) and
706
- impliesStep ( g0 , v0 , guard , v )
707
- )
708
- or
709
- exists ( Guard g0 , GuardValue v0 |
710
- guardControlsBranchEdge ( g0 , bb1 , bb2 , v0 ) and
711
- unboundImpliesStep ( g0 , v0 , guard , v )
712
- )
713
- or
714
- exists ( SsaDefinition def0 , GuardValue v0 |
715
- ssaControlsBranchEdge ( def0 , bb1 , bb2 , v0 ) and
716
- impliesStepSsaGuard ( def0 , v0 , guard , v )
767
+ g0 .hasValueBranchEdge ( bb1 , bb2 , v0 ) and
768
+ BranchImplies:: guardControls ( guard , v , g0 , v0 )
717
769
)
718
770
}
719
771
720
- pragma [ nomagic]
721
- private predicate ssaControlsBranchEdge (
722
- SsaDefinition def , BasicBlock bb1 , BasicBlock bb2 , GuardValue v
723
- ) {
724
- exists ( Guard g0 |
725
- guardControlsBranchEdge ( g0 , bb1 , bb2 , v ) and
726
- guardReadsSsaVar ( g0 , def )
727
- )
728
- or
729
- exists ( SsaDefinition def0 |
730
- ssaControlsBranchEdge ( def0 , bb1 , bb2 , v ) and
731
- impliesStepSsa ( def0 , v , def )
732
- )
772
+ signature module CustomGuardInputSig {
773
+ class ParameterPosition {
774
+ /** Gets a textual representation of this element. */
775
+ bindingset [ this ]
776
+ string toString ( ) ;
777
+ }
778
+
779
+ class ArgumentPosition {
780
+ /** Gets a textual representation of this element. */
781
+ bindingset [ this ]
782
+ string toString ( ) ;
783
+ }
784
+
785
+ /**
786
+ * Holds if the parameter position `ppos` matches the argument position
787
+ * `apos`.
788
+ */
789
+ predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) ;
790
+
791
+ /** A non-overridable method with a boolean return value. */
792
+ class BooleanMethod {
793
+ SsaDefinition getParameter ( ParameterPosition ppos ) ;
794
+
795
+ Expr getAReturnExpr ( ) ;
796
+ }
797
+
798
+ class BooleanMethodCall extends Expr {
799
+ BooleanMethod getMethod ( ) ;
800
+
801
+ Expr getArgument ( ArgumentPosition apos ) ;
802
+ }
803
+ }
804
+
805
+ /**
806
+ * Provides an implementation of guard implication logic for custom
807
+ * wrappers. This can be used to instantiate the `additionalImpliesStep`
808
+ * predicate.
809
+ */
810
+ module CustomGuard< CustomGuardInputSig CustomGuardInput> {
811
+ private import CustomGuardInput
812
+
813
+ private class ReturnExpr extends ExprFinal {
814
+ ReturnExpr ( ) { any ( BooleanMethod m ) .getAReturnExpr ( ) = this }
815
+
816
+ pragma [ nomagic]
817
+ BasicBlock getBasicBlock ( ) { result = super .getBasicBlock ( ) }
818
+ }
819
+
820
+ private predicate booleanReturnGuard ( Guard guard , GuardValue val ) {
821
+ guard instanceof ReturnExpr and exists ( val .asBooleanValue ( ) )
822
+ }
823
+
824
+ private module ReturnImplies = ImpliesTC< booleanReturnGuard / 2 > ;
825
+
826
+ /**
827
+ * Holds if `ret` is a return expression in a non-overridable method that
828
+ * on a return value of `retval` allows the conclusion that the `ppos`th
829
+ * parameter has the value `val`.
830
+ */
831
+ private predicate validReturnInCustomGuard (
832
+ ReturnExpr ret , ParameterPosition ppos , boolean retval , GuardValue val
833
+ ) {
834
+ exists ( BooleanMethod m , SsaDefinition param |
835
+ m .getAReturnExpr ( ) = ret and
836
+ m .getParameter ( ppos ) = param and
837
+ not val instanceof TCaseMatch
838
+ |
839
+ exists ( Guard g0 , GuardValue v0 |
840
+ g0 .directlyValueControls ( ret .getBasicBlock ( ) , v0 ) and
841
+ BranchImplies:: ssaControls ( param , val , g0 , v0 ) and
842
+ retval = [ true , false ]
843
+ )
844
+ or
845
+ ReturnImplies:: ssaControls ( param , val , ret ,
846
+ any ( GuardValue r | r .asBooleanValue ( ) = retval ) )
847
+ )
848
+ }
849
+
850
+ /**
851
+ * Gets a non-overridable method with a boolean return value that performs a check
852
+ * on the `ppos`th parameter. A return value equal to `retval` allows us to conclude
853
+ * that the argument has the value `val`.
854
+ */
855
+ private BooleanMethod customGuard ( ParameterPosition ppos , boolean retval , GuardValue val ) {
856
+ forex ( ReturnExpr ret |
857
+ result .getAReturnExpr ( ) = ret and
858
+ not ret .( ConstantExpr ) .asBooleanValue ( ) = retval .booleanNot ( )
859
+ |
860
+ validReturnInCustomGuard ( ret , ppos , retval , val )
861
+ )
862
+ }
863
+
864
+ /**
865
+ * Holds if the assumption that `g1` has been evaluated to `v1` implies that
866
+ * `g2` has been evaluated to `v2`, that is, the evaluation of `g2` to `v2`
867
+ * dominates the evaluation of `g1` to `v1`.
868
+ *
869
+ * This predicate covers the implication steps that arise from calls to
870
+ * custom guard wrappers.
871
+ */
872
+ predicate additionalImpliesStep ( PreGuard g1 , GuardValue v1 , PreGuard g2 , GuardValue v2 ) {
873
+ exists ( BooleanMethodCall call , ParameterPosition ppos , ArgumentPosition apos |
874
+ g1 = call and
875
+ call .getMethod ( ) = customGuard ( ppos , v1 .asBooleanValue ( ) , v2 ) and
876
+ call .getArgument ( apos ) = g2 and
877
+ parameterMatch ( pragma [ only_bind_out ] ( ppos ) , pragma [ only_bind_out ] ( apos ) )
878
+ )
879
+ }
733
880
}
734
881
735
882
/**
0 commit comments