Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 492b114

Browse files
authored
Merge pull request #4445 from hvitved/csharp/sign-analysis-cfg
C#: Use CFG nodes instead of AST nodes in sign/modulus analysis
2 parents 6218a48 + 2af7e1c commit 492b114

28 files changed

Lines changed: 1186 additions & 543 deletions

config/identical-files.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@
345345
"csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
346346
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
347347
],
348+
"C# ControlFlowReachability": [
349+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
350+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
351+
],
348352
"Inline Test Expectations": [
349353
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
350354
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"

csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,22 @@ module ControlFlow {
310310
Split getASplit() { result = splits.getASplit() }
311311
}
312312

313+
/** A control-flow node for an expression. */
314+
class ExprNode extends ElementNode {
315+
Expr e;
316+
317+
ExprNode() { e = unique(Expr e_ | e_ = this.getElement() | e_) }
318+
319+
/** Gets the expression that this control-flow node belongs to. */
320+
Expr getExpr() { result = e }
321+
322+
/** Gets the value of this expression node, if any. */
323+
string getValue() { result = e.getValue() }
324+
325+
/** Gets the type of this expression node. */
326+
Type getType() { result = e.getType() }
327+
}
328+
313329
class Split = SplitImpl;
314330

315331
class FinallySplit = FinallySplitting::FinallySplitImpl;

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,6 @@ private predicate evenlyDivisibleExpr(Expr e, int factor) {
111111
)
112112
}
113113

114-
/**
115-
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
116-
* in an arbitrary 1-based numbering of the input edges to `phi`.
117-
*/
118-
private predicate rankedPhiInput(
119-
SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int r
120-
) {
121-
edge.phiInput(phi, inp) and
122-
edge =
123-
rank[r](SsaReadPositionPhiInputEdge e | e.phiInput(phi, _) | e order by getId(e.getOrigBlock()))
124-
}
125-
126114
/**
127115
* Holds if `rix` is the number of input edges to `phi`.
128116
*/

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,41 @@
66
* three-valued domain `{negative, zero, positive}`.
77
*/
88

9-
import semmle.code.csharp.dataflow.internal.rangeanalysis.SignAnalysisCommon
9+
import csharp
10+
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SignAnalysisCommon as Common
11+
12+
/** Holds if `e` can be positive and cannot be negative. */
13+
predicate positiveExpr(Expr e) {
14+
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() |
15+
positive(cfn) or strictlyPositive(cfn)
16+
)
17+
}
18+
19+
/** Holds if `e` can be negative and cannot be positive. */
20+
predicate negativeExpr(Expr e) {
21+
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() |
22+
negative(cfn) or strictlyNegative(cfn)
23+
)
24+
}
25+
26+
/** Holds if `e` is strictly positive. */
27+
predicate strictlyPositiveExpr(Expr e) {
28+
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() | strictlyPositive(cfn))
29+
}
30+
31+
/** Holds if `e` is strictly negative. */
32+
predicate strictlyNegativeExpr(Expr e) {
33+
forex(ControlFlow::Node cfn | cfn = e.getAControlFlowNode() | strictlyNegative(cfn))
34+
}
35+
36+
/** Holds if `e` can be positive and cannot be negative. */
37+
predicate positive(ControlFlow::Nodes::ExprNode e) { Common::positive(e) }
38+
39+
/** Holds if `e` can be negative and cannot be positive. */
40+
predicate negative(ControlFlow::Nodes::ExprNode e) { Common::negative(e) }
41+
42+
/** Holds if `e` is strictly positive. */
43+
predicate strictlyPositive(ControlFlow::Nodes::ExprNode e) { Common::strictlyPositive(e) }
44+
45+
/** Holds if `e` is strictly negative. */
46+
predicate strictlyNegative(ControlFlow::Nodes::ExprNode e) { Common::strictlyNegative(e) }

csharp/ql/src/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import csharp
2-
private import DataFlowPrivate
3-
private import DataFlowPublic
42

53
private class ControlFlowScope extends ControlFlowElement {
64
private boolean exactScope;
@@ -89,21 +87,21 @@ abstract class ControlFlowReachabilityConfiguration extends string {
8987

9088
pragma[nomagic]
9189
private predicate reachesBasicBlockExprBase(
92-
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
93-
ControlFlow::Nodes::ElementNode cfn1, int i, ControlFlow::BasicBlock bb
90+
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i,
91+
ControlFlow::BasicBlock bb
9492
) {
95-
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
93+
this.candidate(e1, e2, _, _, isSuccessor) and
9694
cfn1 = e1.getAControlFlowNode() and
9795
bb.getNode(i) = cfn1
9896
}
9997

10098
pragma[nomagic]
10199
private predicate reachesBasicBlockExprRec(
102-
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
103-
ControlFlow::Nodes::ElementNode cfn1, ControlFlow::BasicBlock bb
100+
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
101+
ControlFlow::BasicBlock bb
104102
) {
105103
exists(ControlFlow::BasicBlock mid |
106-
this.reachesBasicBlockExpr(e1, e2, scope, exactScope, isSuccessor, cfn1, mid)
104+
this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid)
107105
|
108106
isSuccessor = true and
109107
bb = mid.getASuccessor()
@@ -115,36 +113,35 @@ abstract class ControlFlowReachabilityConfiguration extends string {
115113

116114
pragma[nomagic]
117115
private predicate reachesBasicBlockExpr(
118-
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
119-
ControlFlow::Nodes::ElementNode cfn1, ControlFlow::BasicBlock bb
116+
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
117+
ControlFlow::BasicBlock bb
120118
) {
121-
this.reachesBasicBlockExprBase(e1, e2, scope, exactScope, isSuccessor, cfn1, _, bb)
119+
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb)
122120
or
123-
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
124-
exists(ControlFlowElement scope0, boolean exactScope0 |
125-
this.reachesBasicBlockExprRec(e1, e2, scope0, exactScope0, isSuccessor, cfn1, bb)
126-
|
127-
bb = getABasicBlockInScope(scope0, exactScope0)
121+
exists(ControlFlowElement scope, boolean exactScope |
122+
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
123+
this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and
124+
bb = getABasicBlockInScope(scope, exactScope)
128125
)
129126
}
130127

131128
pragma[nomagic]
132129
private predicate reachesBasicBlockDefinitionBase(
133-
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
134-
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, int i, ControlFlow::BasicBlock bb
130+
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
131+
int i, ControlFlow::BasicBlock bb
135132
) {
136-
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
133+
this.candidateDef(e, def, _, _, isSuccessor) and
137134
cfn = e.getAControlFlowNode() and
138135
bb.getNode(i) = cfn
139136
}
140137

141138
pragma[nomagic]
142139
private predicate reachesBasicBlockDefinitionRec(
143-
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
144-
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, ControlFlow::BasicBlock bb
140+
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
141+
ControlFlow::BasicBlock bb
145142
) {
146143
exists(ControlFlow::BasicBlock mid |
147-
this.reachesBasicBlockDefinition(e, def, scope, exactScope, isSuccessor, cfn, mid)
144+
this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid)
148145
|
149146
isSuccessor = true and
150147
bb = mid.getASuccessor()
@@ -156,16 +153,15 @@ abstract class ControlFlowReachabilityConfiguration extends string {
156153

157154
pragma[nomagic]
158155
private predicate reachesBasicBlockDefinition(
159-
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
160-
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, ControlFlow::BasicBlock bb
156+
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
157+
ControlFlow::BasicBlock bb
161158
) {
162-
this.reachesBasicBlockDefinitionBase(e, def, scope, exactScope, isSuccessor, cfn, _, bb)
159+
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb)
163160
or
164-
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
165-
exists(ControlFlowElement scope0, boolean exactScope0 |
166-
this.reachesBasicBlockDefinitionRec(e, def, scope0, exactScope0, isSuccessor, cfn, bb)
167-
|
168-
bb = getABasicBlockInScope(scope0, exactScope0)
161+
exists(ControlFlowElement scope, boolean exactScope |
162+
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
163+
this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and
164+
bb = getABasicBlockInScope(scope, exactScope)
169165
)
170166
}
171167

@@ -176,7 +172,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
176172
pragma[nomagic]
177173
predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) {
178174
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
179-
this.reachesBasicBlockExprBase(e1, e2, _, _, isSuccessor, cfn1, i, bb) and
175+
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and
180176
cfn2 = bb.getNode(j) and
181177
cfn2 = e2.getAControlFlowNode()
182178
|
@@ -186,7 +182,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
186182
)
187183
or
188184
exists(ControlFlow::BasicBlock bb |
189-
this.reachesBasicBlockExprRec(e1, e2, _, _, _, cfn1, bb) and
185+
this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and
190186
cfn2 = bb.getANode() and
191187
cfn2 = e2.getAControlFlowNode()
192188
)
@@ -201,7 +197,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
201197
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef
202198
) {
203199
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
204-
this.reachesBasicBlockDefinitionBase(e, def, _, _, isSuccessor, cfn, i, bb) and
200+
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and
205201
cfnDef = bb.getNode(j) and
206202
def.getAControlFlowNode() = cfnDef
207203
|
@@ -211,35 +207,9 @@ abstract class ControlFlowReachabilityConfiguration extends string {
211207
)
212208
or
213209
exists(ControlFlow::BasicBlock bb |
214-
this.reachesBasicBlockDefinitionRec(e, def, _, _, _, cfn, bb) and
210+
this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and
215211
def.getAControlFlowNode() = cfnDef and
216212
cfnDef = bb.getANode()
217213
)
218214
}
219-
220-
/**
221-
* Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an
222-
* expression node or an SSA definition node.
223-
*/
224-
pragma[nomagic]
225-
predicate hasNodePath(ExprNode n1, Node n2) {
226-
exists(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2 |
227-
this.hasExprPath(e1, cfn1, e2, cfn2)
228-
|
229-
cfn1 = n1.getControlFlowNode() and
230-
cfn2 = n2.(ExprNode).getControlFlowNode()
231-
)
232-
or
233-
exists(
234-
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef,
235-
Ssa::ExplicitDefinition ssaDef
236-
|
237-
this.hasDefPath(e, cfn, def, cfnDef)
238-
|
239-
cfn = n1.getControlFlowNode() and
240-
ssaDef.getADefinition() = def and
241-
ssaDef.getControlFlowNode() = cfnDef and
242-
n2.(SsaDefinitionNode).getDefinition() = ssaDef
243-
)
244-
}
245215
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,32 @@ private module ThisFlow {
122122
}
123123
}
124124

125+
/**
126+
* Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an
127+
* expression node or an SSA definition node.
128+
*/
129+
pragma[nomagic]
130+
predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, Node n2) {
131+
exists(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2 |
132+
conf.hasExprPath(e1, cfn1, e2, cfn2)
133+
|
134+
cfn1 = n1.getControlFlowNode() and
135+
cfn2 = n2.(ExprNode).getControlFlowNode()
136+
)
137+
or
138+
exists(
139+
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef,
140+
Ssa::ExplicitDefinition ssaDef
141+
|
142+
conf.hasDefPath(e, cfn, def, cfnDef)
143+
|
144+
cfn = n1.getControlFlowNode() and
145+
ssaDef.getADefinition() = def and
146+
ssaDef.getControlFlowNode() = cfnDef and
147+
n2.(SsaDefinitionNode).getDefinition() = ssaDef
148+
)
149+
}
150+
125151
/** Provides predicates related to local data flow. */
126152
module LocalFlow {
127153
private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -307,7 +333,7 @@ module LocalFlow {
307333
not usesInstanceField(def)
308334
)
309335
or
310-
any(LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo)
336+
hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo)
311337
or
312338
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
313339
or
@@ -669,7 +695,7 @@ private module Cached {
669695
cached
670696
predicate storeStepImpl(Node node1, Content c, Node node2) {
671697
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
672-
x.hasNodePath(node1, node) and
698+
hasNodePath(x, node1, node) and
673699
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
674700
|
675701
fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate)
@@ -704,10 +730,10 @@ private module Cached {
704730
cached
705731
predicate readStepImpl(Node node1, Content c, Node node2) {
706732
exists(ReadStepConfiguration x |
707-
x.hasNodePath(node1, node2) and
733+
hasNodePath(x, node1, node2) and
708734
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
709735
or
710-
x.hasNodePath(node1, node2) and
736+
hasNodePath(x, node1, node2) and
711737
arrayRead(node1.asExpr(), node2.asExpr()) and
712738
c instanceof ElementContent
713739
or
@@ -719,7 +745,7 @@ private module Cached {
719745
c instanceof ElementContent
720746
)
721747
or
722-
x.hasNodePath(node1, node2) and
748+
hasNodePath(x, node1, node2) and
723749
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
724750
c = getResultContent()
725751
)

csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
105105

106106
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
107107
Stages::DataFlowStage::forceCachingInSameStage() and
108-
any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo)
108+
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
109109
or
110110
localTaintStepCil(nodeFrom, nodeTo)
111111
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/BoundSpecific.qll

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55
private import csharp as CS
66
private import semmle.code.csharp.dataflow.SSA::Ssa as Ssa
77
private import semmle.code.csharp.dataflow.internal.rangeanalysis.ConstantUtils as CU
8+
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
9+
private import semmle.code.csharp.dataflow.internal.rangeanalysis.SsaUtils as SU
810

9-
class SsaVariable extends Ssa::Definition {
10-
/** Gets a read of the source variable underlying this SSA definition. */
11-
Expr getAUse() { result = getARead() }
12-
}
11+
class SsaVariable = SU::SsaVariable;
1312

14-
class Expr = CS::Expr;
13+
class Expr = CS::ControlFlow::Nodes::ExprNode;
1514

1615
class IntegralType = CS::IntegralType;
1716

1817
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
1918

2019
/** Holds if `e` is a bound expression and it is not an SSA variable read. */
21-
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.(CS::PropertyRead)) }
20+
predicate interestingExprBound(Expr e) { CU::systemArrayLengthAccess(e.getExpr()) }

0 commit comments

Comments
 (0)