Skip to content

Commit 5c2804d

Browse files
authored
Merge pull request #968 from hvitved/csharp/dataflow-performance
C#: Improve join orders in `DataFlow` module
2 parents cd9ccd4 + 74377a2 commit 5c2804d

File tree

1 file changed

+53
-21
lines changed

1 file changed

+53
-21
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,32 @@ module DataFlow {
710710
override CIL::Expr getArgument(int i) { result = call.getArgument(i) }
711711
}
712712

713+
private ControlFlowElement getAScope(boolean exactScope) {
714+
exists(ExprStepConfiguration c |
715+
c.stepsToExpr(_, _, result, exactScope, _) or
716+
c.stepsToDefinition(_, _, result, exactScope, _)
717+
)
718+
}
719+
720+
private ControlFlowElement getANonExactScopeChild(ControlFlowElement scope) {
721+
scope = getAScope(false) and
722+
result = scope
723+
or
724+
result = getANonExactScopeChild(scope).getAChild()
725+
}
726+
727+
pragma[noinline]
728+
private ControlFlow::BasicBlock getABasicBlockInScope(
729+
ControlFlowElement scope, boolean exactScope
730+
) {
731+
result.getANode().getElement() = getANonExactScopeChild(scope) and
732+
exactScope = false
733+
or
734+
scope = getAScope(true) and
735+
result.getANode().getElement() = scope and
736+
exactScope = true
737+
}
738+
713739
/**
714740
* A helper class for defining expression-based data flow steps, while properly
715741
* taking control flow into account.
@@ -745,6 +771,7 @@ module DataFlow {
745771
none()
746772
}
747773

774+
pragma[nomagic]
748775
private predicate reachesBasicBlockExprRec(
749776
Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope,
750777
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb
@@ -769,20 +796,17 @@ module DataFlow {
769796
cfnFrom = exprFrom.getAControlFlowNode() and
770797
bb = cfnFrom.getBasicBlock()
771798
or
799+
this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor) and
772800
exists(ControlFlowElement scope0, boolean exactScope0 |
773801
this
774802
.reachesBasicBlockExprRec(exprFrom, exprTo, scope0, exactScope0, isSuccessor, cfnFrom,
775-
bb) and
776-
this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor)
803+
bb)
777804
|
778-
exactScope0 = false and
779-
bb.getANode().getElement() = scope0.getAChild*()
780-
or
781-
exactScope0 = true and
782-
bb.getANode().getElement() = scope0
805+
bb = getABasicBlockInScope(scope0, exactScope0)
783806
)
784807
}
785808

809+
pragma[nomagic]
786810
private predicate reachesBasicBlockDefinitionRec(
787811
Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope,
788812
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb
@@ -809,17 +833,13 @@ module DataFlow {
809833
cfnFrom = exprFrom.getAControlFlowNode() and
810834
bb = cfnFrom.getBasicBlock()
811835
or
836+
this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor) and
812837
exists(ControlFlowElement scope0, boolean exactScope0 |
813838
this
814839
.reachesBasicBlockDefinitionRec(exprFrom, defTo, scope0, exactScope0, isSuccessor,
815-
cfnFrom, bb) and
816-
this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor)
840+
cfnFrom, bb)
817841
|
818-
exactScope0 = false and
819-
bb.getANode().getElement() = scope0.getAChild*()
820-
or
821-
exactScope0 = true and
822-
bb.getANode().getElement() = scope0
842+
bb = getABasicBlockInScope(scope0, exactScope0)
823843
)
824844
}
825845

@@ -1030,13 +1050,20 @@ module DataFlow {
10301050
)
10311051
}
10321052

1033-
private Expr getALibraryFlowParent(Expr exprFrom, Expr exprTo, boolean preservesValue) {
1053+
private Expr getALibraryFlowParentFrom(Expr exprFrom, Expr exprTo, boolean preservesValue) {
10341054
libraryFlow(exprFrom, exprTo, preservesValue) and
10351055
result = exprFrom
10361056
or
1037-
exists(Expr mid | mid = getALibraryFlowParent(exprFrom, exprTo, preservesValue) |
1057+
result.getAChildExpr() = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue)
1058+
}
1059+
1060+
private Expr getALibraryFlowParentTo(Expr exprFrom, Expr exprTo, boolean preservesValue) {
1061+
libraryFlow(exprFrom, exprTo, preservesValue) and
1062+
result = exprTo
1063+
or
1064+
exists(Expr mid | mid = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) |
10381065
result.getAChildExpr() = mid and
1039-
not mid.getAChildExpr*() = exprTo
1066+
not mid = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue)
10401067
)
10411068
}
10421069

@@ -1045,8 +1072,8 @@ module DataFlow {
10451072
) {
10461073
// To not pollute the definitions in `LibraryTypeDataFlow.qll` with syntactic scope,
10471074
// simply use the nearest common parent expression for `exprFrom` and `exprTo`
1048-
scope = getALibraryFlowParent(exprFrom, exprTo, preservesValue) and
1049-
scope.getAChildExpr*() = exprTo and
1075+
scope = getALibraryFlowParentFrom(exprFrom, exprTo, preservesValue) and
1076+
scope = getALibraryFlowParentTo(exprFrom, exprTo, preservesValue) and
10501077
// Similarly, for simplicity allow following both forwards and backwards edges from
10511078
// `exprFrom` to `exprTo`
10521079
(isSuccessor = true or isSuccessor = false)
@@ -1220,6 +1247,12 @@ module DataFlow {
12201247
LocalFlow::localFlowStep(pred, succ, config)
12211248
}
12221249

1250+
pragma[noinline]
1251+
private predicate jumpStepCand1(Node pred, Node succ, Configuration config) {
1252+
nodeCand1(succ, config) and
1253+
jumpStep(pred, succ)
1254+
}
1255+
12231256
pragma[noinline]
12241257
predicate flowIntoCallableStepCand1(
12251258
CallNode call, ArgumentNode arg, ParameterNode p, Configuration config
@@ -1249,9 +1282,8 @@ module DataFlow {
12491282
localFlowStepCand1(mid, node, config)
12501283
)
12511284
or
1252-
nodeCand1(node, config) and
12531285
exists(Node mid | nodeCandFwd2(mid, _, config) |
1254-
jumpStep(mid, node) and
1286+
jumpStepCand1(mid, node, config) and
12551287
fromArg = false
12561288
)
12571289
or

0 commit comments

Comments
 (0)