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

Skip to content

Commit 2af7e1c

Browse files
committed
C#: Use CFG nodes instead of AST nodes in sign/modulus analysis
1 parent 952b2da commit 2af7e1c

23 files changed

Lines changed: 905 additions & 477 deletions

File tree

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/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()) }

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

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,10 @@
44

55
private import csharp
66
private import Ssa
7+
private import SsaUtils
8+
private import RangeUtils
79

8-
/**
9-
* Holds if property `p` matches `property` in `baseClass` or any overrides.
10-
*/
11-
predicate propertyOverrides(Property p, string baseClass, string property) {
12-
exists(Property p2 |
13-
p2.getSourceDeclaration().getDeclaringType().hasQualifiedName(baseClass) and
14-
p2.hasName(property)
15-
|
16-
p.overridesOrImplementsOrEquals(p2)
17-
)
18-
}
10+
private class ExprNode = ControlFlow::Nodes::ExprNode;
1911

2012
/**
2113
* Holds if `pa` is an access to the `Length` property of an array.
@@ -30,40 +22,42 @@ predicate systemArrayLengthAccess(PropertyAccess pa) {
3022
* - a read of a compile time constant with integer value `val`, or
3123
* - a read of the `Length` of an array with `val` lengths.
3224
*/
33-
private predicate constantIntegerExpr(Expr e, int val) {
25+
private predicate constantIntegerExpr(ExprNode e, int val) {
3426
e.getValue().toInt() = val
3527
or
36-
exists(ExplicitDefinition v, Expr src |
37-
e = v.getARead() and
38-
src = v.getADefinition().getSource() and
28+
exists(ExprNode src |
29+
e = getAnExplicitDefinitionRead(src) and
3930
constantIntegerExpr(src, val)
4031
)
4132
or
4233
isArrayLengthAccess(e, val)
4334
}
4435

45-
private int getArrayLength(ArrayCreation arrCreation, int index) {
46-
constantIntegerExpr(arrCreation.getLengthArgument(index), result)
36+
private int getArrayLength(ExprNode e, int index) {
37+
exists(ArrayCreation arrCreation, ExprNode length |
38+
hasChild(arrCreation, arrCreation.getLengthArgument(index), e, length) and
39+
constantIntegerExpr(length, result)
40+
)
4741
}
4842

49-
private int getArrayLengthRec(ArrayCreation arrCreation, int index) {
43+
private int getArrayLengthRec(ExprNode arrCreation, int index) {
5044
index = 0 and result = getArrayLength(arrCreation, 0)
5145
or
5246
index > 0 and
5347
result = getArrayLength(arrCreation, index) * getArrayLengthRec(arrCreation, index - 1)
5448
}
5549

56-
private predicate isArrayLengthAccess(PropertyAccess pa, int length) {
57-
systemArrayLengthAccess(pa) and
58-
exists(ExplicitDefinition arr, ArrayCreation arrCreation |
59-
getArrayLengthRec(arrCreation, arrCreation.getNumberOfLengthArguments() - 1) = length and
60-
arrCreation = arr.getADefinition().getSource() and
61-
pa.getQualifier() = arr.getARead()
50+
private predicate isArrayLengthAccess(ExprNode e, int length) {
51+
exists(PropertyAccess pa, ExprNode arrCreation |
52+
systemArrayLengthAccess(pa) and
53+
getArrayLengthRec(arrCreation,
54+
arrCreation.getExpr().(ArrayCreation).getNumberOfLengthArguments() - 1) = length and
55+
hasChild(pa, pa.getQualifier(), e, getAnExplicitDefinitionRead(arrCreation))
6256
)
6357
}
6458

6559
/** An expression that always has the same integer value. */
66-
class ConstantIntegerExpr extends Expr {
60+
class ConstantIntegerExpr extends ExprNode {
6761
ConstantIntegerExpr() { constantIntegerExpr(this, _) }
6862

6963
/** Gets the integer value of this expression. */
Lines changed: 49 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,84 @@
11
module Private {
22
private import csharp as CS
33
private import ConstantUtils as CU
4-
private import semmle.code.csharp.controlflow.Guards as G
54
private import semmle.code.csharp.dataflow.internal.rangeanalysis.RangeUtils as RU
65
private import SsaUtils as SU
7-
private import SignAnalysisSpecific::Private as SA
6+
private import SsaReadPositionCommon
87

98
class BasicBlock = CS::Ssa::BasicBlock;
109

11-
class SsaVariable extends CS::Ssa::Definition {
12-
CS::AssignableRead getAUse() { result = this.getARead() }
13-
}
10+
class SsaVariable = SU::SsaVariable;
1411

1512
class SsaPhiNode = CS::Ssa::PhiNode;
1613

17-
class Expr = CS::Expr;
14+
class Expr = CS::ControlFlow::Nodes::ExprNode;
1815

19-
class Guard = G::Guard;
16+
class Guard = RU::Guard;
2017

2118
class ConstantIntegerExpr = CU::ConstantIntegerExpr;
2219

23-
class ConditionalExpr extends CS::ConditionalExpr {
24-
/** Gets the "then" expression of this conditional expression. */
25-
Expr getTrueExpr() { result = this.getThen() }
20+
class ConditionalExpr = RU::ExprNode::ConditionalExpr;
2621

27-
/** Gets the "else" expression of this conditional expression. */
28-
Expr getFalseExpr() { result = this.getElse() }
29-
}
22+
class AddExpr = RU::ExprNode::AddExpr;
3023

31-
/** Represent an addition expression. */
32-
class AddExpr extends CS::AddExpr {
33-
/** Gets the LHS operand of this add expression. */
34-
Expr getLhs() { result = this.getLeftOperand() }
24+
class SubExpr = RU::ExprNode::SubExpr;
3525

36-
/** Gets the RHS operand of this add expression. */
37-
Expr getRhs() { result = this.getRightOperand() }
38-
}
26+
class RemExpr = RU::ExprNode::RemExpr;
3927

40-
/** Represent a subtraction expression. */
41-
class SubExpr extends CS::SubExpr {
42-
/** Gets the LHS operand of this subtraction expression. */
43-
Expr getLhs() { result = this.getLeftOperand() }
28+
class BitwiseAndExpr = RU::ExprNode::BitwiseAndExpr;
4429

45-
/** Gets the RHS operand of this subtraction expression. */
46-
Expr getRhs() { result = this.getRightOperand() }
47-
}
30+
class MulExpr = RU::ExprNode::MulExpr;
4831

49-
class RemExpr = CS::RemExpr;
50-
51-
/** Represent a bitwise and or an assign-and expression. */
52-
class BitwiseAndExpr extends CS::Expr {
53-
BitwiseAndExpr() { this instanceof CS::BitwiseAndExpr or this instanceof CS::AssignAndExpr }
54-
55-
/** Gets an operand of this bitwise and operation. */
56-
Expr getAnOperand() {
57-
result = this.(CS::BitwiseAndExpr).getAnOperand() or
58-
result = this.(CS::AssignAndExpr).getRValue() or
59-
result = this.(CS::AssignAndExpr).getLValue()
60-
}
61-
62-
/** Holds if this expression has operands `e1` and `e2`. */
63-
predicate hasOperands(Expr e1, Expr e2) {
64-
this.getAnOperand() = e1 and
65-
this.getAnOperand() = e2 and
66-
e1 != e2
67-
}
68-
}
32+
class LShiftExpr = RU::ExprNode::LShiftExpr;
6933

70-
/** Represent a multiplication or an assign-mul expression. */
71-
class MulExpr extends CS::Expr {
72-
MulExpr() { this instanceof CS::MulExpr or this instanceof CS::AssignMulExpr }
34+
predicate guardDirectlyControlsSsaRead = RU::guardControlsSsaRead/3;
7335

74-
/** Gets an operand of this multiplication. */
75-
Expr getAnOperand() {
76-
result = this.(CS::MulExpr).getAnOperand() or
77-
result = this.(CS::AssignMulExpr).getRValue() or
78-
result = this.(CS::AssignMulExpr).getLValue()
79-
}
80-
}
36+
predicate guardControlsSsaRead = RU::guardControlsSsaRead/3;
8137

82-
/** Represent a left shift or an assign-lshift expression. */
83-
class LShiftExpr extends CS::Expr {
84-
LShiftExpr() { this instanceof CS::LShiftExpr or this instanceof CS::AssignLShiftExpr }
38+
predicate valueFlowStep = RU::valueFlowStep/3;
8539

86-
/** Gets the RHS operand of this shift. */
87-
Expr getRhs() {
88-
result = this.(CS::LShiftExpr).getRightOperand() or
89-
result = this.(CS::AssignLShiftExpr).getRValue()
90-
}
91-
}
40+
predicate eqFlowCond = RU::eqFlowCond/5;
9241

93-
predicate guardDirectlyControlsSsaRead = SA::guardControlsSsaRead/3;
42+
predicate ssaUpdateStep = RU::ssaUpdateStep/3;
9443

95-
predicate guardControlsSsaRead = SA::guardControlsSsaRead/3;
44+
Expr getABasicBlockExpr(BasicBlock bb) { result = bb.getANode() }
9645

97-
predicate valueFlowStep = RU::valueFlowStep/3;
46+
private class CallableOrCFE extends CS::Element {
47+
CallableOrCFE() { this instanceof CS::Callable or this instanceof CS::ControlFlowElement }
48+
}
9849

99-
predicate eqFlowCond = RU::eqFlowCond/5;
50+
private predicate id(CallableOrCFE x, CallableOrCFE y) { x = y }
10051

101-
predicate ssaUpdateStep = RU::ssaUpdateStep/3;
52+
private predicate idOf(CallableOrCFE x, int y) = equivalenceRelation(id/2)(x, y)
10253

103-
Expr getABasicBlockExpr(BasicBlock bb) { result = bb.getANode().getElement() }
54+
private class PhiInputEdgeBlock extends BasicBlock {
55+
PhiInputEdgeBlock() { this = any(SsaReadPositionPhiInputEdge edge).getOrigBlock() }
56+
}
10457

105-
private predicate id(CS::ControlFlowElement x, CS::ControlFlowElement y) { x = y }
58+
int getId(PhiInputEdgeBlock bb) {
59+
idOf(bb.getFirstNode().getElement(), result)
60+
or
61+
idOf(bb.(CS::ControlFlow::BasicBlocks::EntryBlock).getCallable(), result)
62+
}
10663

107-
private predicate idOf(CS::ControlFlowElement x, int y) = equivalenceRelation(id/2)(x, y)
64+
private string getSplitString(PhiInputEdgeBlock bb) {
65+
result = bb.getFirstNode().(CS::ControlFlow::Nodes::ElementNode).getSplitsString()
66+
or
67+
not exists(bb.getFirstNode().(CS::ControlFlow::Nodes::ElementNode).getSplitsString()) and
68+
result = ""
69+
}
10870

109-
int getId(BasicBlock bb) { idOf(bb.getFirstNode().getElement(), result) }
71+
/**
72+
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
73+
* in an arbitrary 1-based numbering of the input edges to `phi`.
74+
*/
75+
predicate rankedPhiInput(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge, int r) {
76+
edge.phiInput(phi, inp) and
77+
edge =
78+
rank[r](SsaReadPositionPhiInputEdge e |
79+
e.phiInput(phi, _)
80+
|
81+
e order by getId(e.getOrigBlock()), getSplitString(e.getOrigBlock())
82+
)
83+
}
11084
}

0 commit comments

Comments
 (0)