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

Skip to content

Commit d175550

Browse files
committed
C#: Data flow through fields
Initial implementation of data flow through fields, using the algorithm of the shared data flow implementation. Fields (and field-like properties) are covered, and stores can be either - ordinary assignments, `Foo = x`, - object initializers, `new C() { Foo = x }`, or - field initializers, `int Foo = x`. For field initializers, we need to synthesize calls (`SynthesizedCall`), callables (`SynthesizedCallable`), parameters (`InstanceParameterNode`), and arguments (`SynthesizedThisArgumentNode`), as the C# extractor does not (yet) extract such entities. For example, in ``` class C { int Field1 = 1; int Field2 = 2; C() { } } ``` there is a synthesized call from the constructor `C`, with a synthesized `this` argument, and the targets of that call are two synthesized callables with bodies `this.Field1 = 1` and `this.Field2 = 2`, respectively. A consequence of this is that `DataFlowCallable` is no longer an alias for `DotNet::Callable`, but instead an IPA type.
1 parent b7e732f commit d175550

27 files changed

Lines changed: 1527 additions & 145 deletions

csharp/ql/src/semmle/code/csharp/AnnotatedType.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ class AnnotatedType extends TAnnotatedType {
182182

183183
/** Gets a textual representation of this annotated type. */
184184
string toString() {
185-
result = annotations.getTypePrefix() + getUnderlyingType().toStringWithTypes() + annotations.getTypeSuffix()
185+
result = annotations.getTypePrefix() + getUnderlyingType().toStringWithTypes() +
186+
annotations.getTypeSuffix()
186187
}
187188

188189
/** Gets the location of this annotated type. */

csharp/ql/src/semmle/code/csharp/Assignable.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ module AssignableDefinitions {
726726
class InitializerDefinition extends AssignmentDefinition {
727727
private Assignable fieldOrProp;
728728

729-
InitializerDefinition() { this.getAssignment().getParent() = fieldOrProp}
729+
InitializerDefinition() { this.getAssignment().getParent() = fieldOrProp }
730730

731731
/** Gets the assignable (field or property) being initialized. */
732732
Assignable getAssignable() { result = fieldOrProp }

csharp/ql/src/semmle/code/csharp/Callable.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,10 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, Cont
2727
final AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) }
2828

2929
/** DEPRECATED: Use `getAnnotatedReturnType().isRef()` instead. */
30-
deprecated predicate returnsRef() {
31-
this.getAnnotatedReturnType().isRef()
32-
}
30+
deprecated predicate returnsRef() { this.getAnnotatedReturnType().isRef() }
3331

3432
/** DEPRECATED: Use `getAnnotatedReturnType().isReadonlyRef()` instead. */
35-
deprecated predicate returnsRefReadonly() {
36-
this.getAnnotatedReturnType().isReadonlyRef()
37-
}
33+
deprecated predicate returnsRefReadonly() { this.getAnnotatedReturnType().isReadonlyRef() }
3834

3935
override Callable getSourceDeclaration() { result = Parameterizable.super.getSourceDeclaration() }
4036

csharp/ql/src/semmle/code/csharp/Property.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ class Property extends DotNet::Property, DeclarationWithGetSetAccessors, @proper
203203
*/
204204
Expr getInitializer() { result = this.getChildExpr(1).getChildExpr(0) }
205205

206+
/**
207+
* Holds if this property has an initial value. For example, the initial
208+
* value of `P` on line 2 is `20` in
209+
*
210+
* ```
211+
* class C {
212+
* public int P { get; set; } = 20;
213+
* }
214+
* ```
215+
*/
216+
predicate hasInitializer() { exists(this.getInitializer()) }
217+
206218
/**
207219
* Gets the expression body of this property, if any. For example, the expression
208220
* body of `P` on line 2 is `20` in

csharp/ql/src/semmle/code/csharp/Variable.qll

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,30 @@ class LocalConstant extends LocalVariable, @local_constant {
364364
*/
365365
class Field extends Variable, AssignableMember, Attributable, TopLevelExprParent, DotNet::Field,
366366
@field {
367-
/** Gets the initializer of this field, if any. */
367+
/**
368+
* Gets the initial value of this field, if any. For example, the initial
369+
* value of `F` on line 2 is `20` in
370+
*
371+
* ```
372+
* class C {
373+
* public int F = 20;
374+
* }
375+
* ```
376+
*/
368377
override Expr getInitializer() { result = this.getChildExpr(0).getChildExpr(0) }
369378

379+
/**
380+
* Holds if this field has an initial value. For example, the initial
381+
* value of `F` on line 2 is `20` in
382+
*
383+
* ```
384+
* class C {
385+
* public int F = 20;
386+
* }
387+
* ```
388+
*/
389+
predicate hasInitializer() { exists(this.getInitializer()) }
390+
370391
/** Holds if this field is `volatile`. */
371392
predicate isVolatile() { this.hasModifier("volatile") }
372393

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private import semmle.code.csharp.Caching
1010
/**
1111
* An element that contains a top-level statement or expression. Either a callable
1212
* (`Callable`), an attribute (`Attribute`), a field (`Field`), a property
13-
* (`Property`), an indexer (`Indexer`), or a parameter (`Parameter`).
13+
* (`Property`), an indexer (`Indexer`), or a parameter (`Parameter`).
1414
*/
1515
class ControlFlowEntryElement extends Element, @top_level_exprorstmt_parent { }
1616

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

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ abstract class ControlFlowReachabilityConfiguration extends string {
8787
none()
8888
}
8989

90+
pragma[nomagic]
91+
private predicate reachesBasicBlockExprBase(
92+
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
93+
ControlFlow::Nodes::ElementNode cfn1, int i, ControlFlow::BasicBlock bb
94+
) {
95+
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
96+
cfn1 = e1.getAControlFlowNode() and
97+
bb.getNode(i) = cfn1
98+
}
99+
90100
pragma[nomagic]
91101
private predicate reachesBasicBlockExprRec(
92102
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
@@ -108,9 +118,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
108118
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor,
109119
ControlFlow::Nodes::ElementNode cfn1, ControlFlow::BasicBlock bb
110120
) {
111-
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
112-
cfn1 = e1.getAControlFlowNode() and
113-
bb = cfn1.getBasicBlock()
121+
this.reachesBasicBlockExprBase(e1, e2, scope, exactScope, isSuccessor, cfn1, _, bb)
114122
or
115123
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
116124
exists(ControlFlowElement scope0, boolean exactScope0 |
@@ -120,6 +128,16 @@ abstract class ControlFlowReachabilityConfiguration extends string {
120128
)
121129
}
122130

131+
pragma[nomagic]
132+
private predicate reachesBasicBlockDefinitionBase(
133+
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
134+
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, int i, ControlFlow::BasicBlock bb
135+
) {
136+
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
137+
cfn = e.getAControlFlowNode() and
138+
bb.getNode(i) = cfn
139+
}
140+
123141
pragma[nomagic]
124142
private predicate reachesBasicBlockDefinitionRec(
125143
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
@@ -141,9 +159,7 @@ abstract class ControlFlowReachabilityConfiguration extends string {
141159
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
142160
boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn, ControlFlow::BasicBlock bb
143161
) {
144-
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
145-
cfn = e.getAControlFlowNode() and
146-
bb = cfn.getBasicBlock()
162+
this.reachesBasicBlockDefinitionBase(e, def, scope, exactScope, isSuccessor, cfn, _, bb)
147163
or
148164
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
149165
exists(ControlFlowElement scope0, boolean exactScope0 |
@@ -158,7 +174,18 @@ abstract class ControlFlowReachabilityConfiguration extends string {
158174
* control-flow node for `e1` and `cfn2` is a control-flow node for `e2`.
159175
*/
160176
predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) {
161-
exists(ControlFlow::BasicBlock bb | this.reachesBasicBlockExpr(e1, e2, _, _, _, cfn1, bb) |
177+
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
178+
this.reachesBasicBlockExprBase(e1, e2, _, _, isSuccessor, cfn1, i, bb) and
179+
cfn2 = bb.getNode(j) and
180+
cfn2 = e2.getAControlFlowNode()
181+
|
182+
isSuccessor = true and j > i
183+
or
184+
isSuccessor = false and i > j
185+
)
186+
or
187+
exists(ControlFlow::BasicBlock bb |
188+
this.reachesBasicBlockExprRec(e1, e2, _, _, _, cfn1, bb) and
162189
cfn2 = bb.getANode() and
163190
cfn2 = e2.getAControlFlowNode()
164191
)
@@ -171,7 +198,18 @@ abstract class ControlFlowReachabilityConfiguration extends string {
171198
predicate hasDefPath(
172199
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef
173200
) {
174-
exists(ControlFlow::BasicBlock bb | this.reachesBasicBlockDefinition(e, def, _, _, _, cfn, bb) |
201+
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
202+
this.reachesBasicBlockDefinitionBase(e, def, _, _, isSuccessor, cfn, i, bb) and
203+
cfnDef = bb.getNode(j) and
204+
def.getAControlFlowNode() = cfnDef
205+
|
206+
isSuccessor = true and j > i
207+
or
208+
isSuccessor = false and i > j
209+
)
210+
or
211+
exists(ControlFlow::BasicBlock bb |
212+
this.reachesBasicBlockDefinitionRec(e, def, _, _, _, cfn, bb) and
175213
def.getAControlFlowNode() = cfnDef and
176214
cfnDef = bb.getANode()
177215
)

0 commit comments

Comments
 (0)