Skip to content

Commit c5d9d74

Browse files
committed
C#: Nested field flow
1 parent 23b74b5 commit c5d9d74

File tree

14 files changed

+252
-92
lines changed

14 files changed

+252
-92
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class AssignableRead extends AssignableAccess {
8181

8282
pragma[noinline]
8383
private ControlFlow::Node getAnAdjacentReadSameVar() {
84-
Ssa::Internal::adjacentReadPairSameVar(this.getAControlFlowNode(), result)
84+
Ssa::Internal::adjacentReadPairSameVar(_, this.getAControlFlowNode(), result)
8585
}
8686

8787
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ private predicate defReaches(Ssa::Definition def, ControlFlow::Node cfn, boolean
462462
(always = true or always = false)
463463
or
464464
exists(ControlFlow::Node mid | defReaches(def, mid, always) |
465-
Ssa::Internal::adjacentReadPairSameVar(mid, cfn) and
465+
Ssa::Internal::adjacentReadPairSameVar(_, mid, cfn) and
466466
not mid = any(Dereference d |
467467
if always = true
468468
then d.isAlwaysNull(def.getSourceVariable())

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -860,13 +860,15 @@ module Ssa {
860860
}
861861

862862
/**
863-
* Holds if the read at `cfn2` is a read of the same SSA definition as the
864-
* read at `cfn1`, and `cfn2` can be reached from `cfn1` without passing
865-
* through another read.
863+
* Holds if the read at `cfn2` is a read of the same SSA definition `def`
864+
* as the read at `cfn1`, and `cfn2` can be reached from `cfn1` without
865+
* passing through another read.
866866
*/
867867
cached
868-
predicate adjacentReadPairSameVar(ControlFlow::Node cfn1, ControlFlow::Node cfn2) {
869-
exists(TrackedDefinition def, BasicBlock bb1, int i1 |
868+
predicate adjacentReadPairSameVar(
869+
TrackedDefinition def, ControlFlow::Node cfn1, ControlFlow::Node cfn2
870+
) {
871+
exists(BasicBlock bb1, int i1 |
870872
variableRead(bb1, i1, _, cfn1, _) and
871873
adjacentVarRead(def, bb1, i1, cfn2)
872874
)
@@ -1115,9 +1117,7 @@ module Ssa {
11151117
}
11161118

11171119
/** Gets a run-time target for the delegate call `c`. */
1118-
Callable getARuntimeDelegateTarget(Call c) {
1119-
delegateCall(c, delegateCallSource(result))
1120-
}
1120+
Callable getARuntimeDelegateTarget(Call c) { delegateCall(c, delegateCallSource(result)) }
11211121
}
11221122

11231123
/** Holds if `(c1,c2)` is an edge in the call graph. */

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

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -297,71 +297,86 @@ private module Cached {
297297
any(DelegateArgumentConfiguration x).hasExprPath(_, cfn, _, call)
298298
} or
299299
TMallocNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof ObjectCreation } or
300-
TArgumentPostCallNode(ControlFlow::Nodes::ElementNode cfn) {
300+
TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) {
301301
exists(Argument a, Type t |
302302
a = cfn.getElement() and
303303
t = a.stripCasts().getType()
304304
|
305305
t instanceof RefType or
306306
t = any(TypeParameter tp | not tp.isValueType())
307307
)
308-
} or
309-
TStoreTargetNode(ControlFlow::Nodes::ElementNode cfn) {
308+
or
310309
instanceFieldLikeAssign(_, _, _, cfn.getElement())
310+
or
311+
exists(TExprPostUpdateNode upd, FieldLikeAccess fla |
312+
upd = TExprPostUpdateNode(fla.getAControlFlowNode())
313+
|
314+
cfn.getElement() = fla.getQualifier()
315+
)
311316
}
312317

313-
/**
314-
* This is the local flow predicate that's used as a building block in global
315-
* data flow. It may have less flow than the `localFlowStep` predicate.
316-
*/
318+
private predicate usesInstanceField(Ssa::Definition def) {
319+
exists(Ssa::SourceVariables::FieldOrPropSourceVariable fp | fp = def.getSourceVariable() |
320+
not fp.getAssignable().isStatic()
321+
)
322+
}
323+
317324
cached
318-
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
319-
any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo)
325+
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo, boolean simple) {
326+
any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) and
327+
simple = true
320328
or
321329
// Flow from SSA definition to first read
322330
exists(Ssa::Definition def, ControlFlow::Node cfn |
323-
def = nodeFrom.(SsaDefinitionNode).getDefinition()
324-
|
325-
nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn)
331+
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
332+
nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn) and
333+
if usesInstanceField(def) then simple = false else simple = true
326334
)
327335
or
328336
// Flow from read to next read
329-
exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
330-
Ssa::Internal::adjacentReadPairSameVar(cfnFrom, cfnTo) and
331-
nodeTo = TExprNode(cfnTo)
337+
exists(Ssa::Definition def, ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
338+
Ssa::Internal::adjacentReadPairSameVar(def, cfnFrom, cfnTo) and
339+
nodeTo = TExprNode(cfnTo) and
340+
if usesInstanceField(def) then simple = false else simple = true
332341
|
333342
nodeFrom = TExprNode(cfnFrom)
334343
or
335344
cfnFrom = nodeFrom.(PostUpdateNode).getPreUpdateNode().getControlFlowNode()
336345
)
337346
or
338-
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
347+
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) and
348+
simple = true
339349
or
340-
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
350+
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) and
351+
simple = true
341352
or
342353
// Flow into SSA pseudo definition
343354
exists(Ssa::Definition def, Ssa::PseudoDefinition pseudo |
344-
LocalFlow::localFlowSsaInput(nodeFrom, def)
345-
|
355+
LocalFlow::localFlowSsaInput(nodeFrom, def) and
346356
pseudo = nodeTo.(SsaDefinitionNode).getDefinition() and
347-
def = pseudo.getAnInput()
357+
def = pseudo.getAnInput() and
358+
if usesInstanceField(def) then simple = false else simple = true
348359
)
349360
or
350361
// Flow into uncertain SSA definition
351362
exists(Ssa::Definition def, LocalFlow::UncertainExplicitSsaDefinition uncertain |
352-
LocalFlow::localFlowSsaInput(nodeFrom, def)
353-
|
363+
LocalFlow::localFlowSsaInput(nodeFrom, def) and
354364
uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and
355-
def = uncertain.getPriorDefinition()
365+
def = uncertain.getPriorDefinition() and
366+
if usesInstanceField(def) then simple = false else simple = true
356367
)
357368
or
358-
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo)
369+
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) and
370+
simple = true
359371
or
360-
flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true)
372+
flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true) and
373+
simple = true
361374
or
362-
flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true)
375+
flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true) and
376+
simple = true
363377
or
364-
LocalFlow::localFlowStepCil(nodeFrom, nodeTo)
378+
LocalFlow::localFlowStepCil(nodeFrom, nodeTo) and
379+
simple = true
365380
}
366381

367382
/**
@@ -409,6 +424,15 @@ private module Cached {
409424
}
410425
import Cached
411426

427+
/**
428+
* This is the local flow predicate that is used as a building block in global
429+
* data flow. It is a strict subset of the `localFlowStep` predicate, as it
430+
* excludes SSA flow through instance fields.
431+
*/
432+
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
433+
localFlowStepImpl(nodeFrom, nodeTo, true)
434+
}
435+
412436
/** An SSA definition, viewed as a node in a data flow graph. */
413437
class SsaDefinitionNode extends Node, TSsaDefinitionNode {
414438
Ssa::Definition def;
@@ -1250,26 +1274,10 @@ private module PostUpdateNodes {
12501274
override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) }
12511275
}
12521276

1253-
private class ArgumentPostCallNode extends PostUpdateNode, TArgumentPostCallNode {
1254-
private ControlFlow::Nodes::ElementNode cfn;
1255-
1256-
ArgumentPostCallNode() { this = TArgumentPostCallNode(cfn) }
1257-
1258-
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
1259-
1260-
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
1261-
1262-
override Type getType() { result = cfn.getElement().(Expr).getType() }
1263-
1264-
override Location getLocation() { result = cfn.getLocation() }
1265-
1266-
override string toString() { result = "[post] " + cfn.toString() }
1267-
}
1268-
1269-
private class StoreTargetNode extends PostUpdateNode, TStoreTargetNode {
1277+
private class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
12701278
private ControlFlow::Nodes::ElementNode cfn;
12711279

1272-
StoreTargetNode() { this = TStoreTargetNode(cfn) }
1280+
ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) }
12731281

12741282
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
12751283

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ ParameterNode parameterNode(DotNet::Parameter p) { result.getParameter() = p }
152152
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
153153
* (intra-procedural) step.
154154
*/
155-
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
155+
predicate localFlowStep(Node nodeFrom, Node nodeTo) { localFlowStepImpl(nodeFrom, nodeTo, _) }
156156

157157
/**
158158
* Holds if data flows from `source` to `sink` in zero or more local

csharp/ql/src/semmle/code/csharp/exprs/Call.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
425425
* }
426426
* ```
427427
*/
428-
predicate isThis() {
429-
this.getTargetType() = this.getConstructorType()
430-
}
428+
predicate isThis() { this.getTargetType() = this.getConstructorType() }
431429

432430
/**
433431
* Holds if this initialier is a `base` initializer, for example `base(0)`
@@ -445,9 +443,7 @@ class ConstructorInitializer extends Call, @constructor_init_expr {
445443
* }
446444
* ```
447445
*/
448-
predicate isBase() {
449-
this.getTargetType() != this.getConstructorType()
450-
}
446+
predicate isBase() { this.getTargetType() != this.getConstructorType() }
451447

452448
/**
453449
* Gets the constructor that this initializer call belongs to. For example,

csharp/ql/test/library-tests/cil/dataflow/TaintTracking.ql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import csharp
22
import semmle.code.csharp.dataflow.TaintTracking
3-
43
// Test that all the copies of the taint tracking library can be imported
54
// simultaneously without errors.
65
import semmle.code.csharp.dataflow.TaintTracking2

csharp/ql/test/library-tests/controlflow/graph/EnclosingCallable.ql

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,4 @@ import Common
33

44
query predicate nodeEnclosing(SourceControlFlowNode n, Callable c) { c = n.getEnclosingCallable() }
55

6-
query predicate blockEnclosing(SourceBasicBlock bb, Callable c) {
7-
c = bb.getCallable()
8-
}
6+
query predicate blockEnclosing(SourceBasicBlock bb, Callable c) { c = bb.getCallable() }

0 commit comments

Comments
 (0)