Skip to content

Commit 982f90d

Browse files
committed
C#: Refactor local data flow step relations
1 parent c5d9d74 commit 982f90d

File tree

2 files changed

+79
-64
lines changed

2 files changed

+79
-64
lines changed

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

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ module LocalFlow {
171171
* Either an SSA definition node for `def` when there is no read of `def`,
172172
* or a last read of `def`.
173173
*/
174-
predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def) {
174+
private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def) {
175175
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
176176
not exists(def.getARead())
177177
or
@@ -180,6 +180,51 @@ module LocalFlow {
180180
)
181181
}
182182

183+
/**
184+
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
185+
* SSA definition `def.
186+
*/
187+
predicate localSsaFlowStep(Ssa::Definition def, Node nodeFrom, Node nodeTo) {
188+
// Flow from SSA definition to first read
189+
exists(ControlFlow::Node cfn |
190+
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
191+
nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn)
192+
)
193+
or
194+
// Flow from read to next read
195+
exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
196+
Ssa::Internal::adjacentReadPairSameVar(def, cfnFrom, cfnTo) and
197+
nodeTo = TExprNode(cfnTo)
198+
|
199+
nodeFrom = TExprNode(cfnFrom)
200+
or
201+
cfnFrom = nodeFrom.(PostUpdateNode).getPreUpdateNode().getControlFlowNode()
202+
)
203+
or
204+
// Flow into SSA pseudo definition
205+
exists(Ssa::PseudoDefinition pseudo |
206+
localFlowSsaInput(nodeFrom, def) and
207+
pseudo = nodeTo.(SsaDefinitionNode).getDefinition() and
208+
def = pseudo.getAnInput()
209+
)
210+
or
211+
// Flow into uncertain SSA definition
212+
exists(LocalFlow::UncertainExplicitSsaDefinition uncertain |
213+
localFlowSsaInput(nodeFrom, def) and
214+
uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and
215+
def = uncertain.getPriorDefinition()
216+
)
217+
}
218+
219+
/**
220+
* Holds if the source variable of SSA definition `def` is an instance field.
221+
*/
222+
predicate usesInstanceField(Ssa::Definition def) {
223+
exists(Ssa::SourceVariables::FieldOrPropSourceVariable fp | fp = def.getSourceVariable() |
224+
not fp.getAssignable().isStatic()
225+
)
226+
}
227+
183228
predicate localFlowCapturedVarStep(SsaDefinitionNode nodeFrom, ImplicitCapturedArgumentNode nodeTo) {
184229
// Flow from SSA definition to implicit captured variable argument
185230
exists(Ssa::ExplicitDefinition def, ControlFlow::Nodes::ElementNode call |
@@ -315,68 +360,43 @@ private module Cached {
315360
)
316361
}
317362

318-
private predicate usesInstanceField(Ssa::Definition def) {
319-
exists(Ssa::SourceVariables::FieldOrPropSourceVariable fp | fp = def.getSourceVariable() |
320-
not fp.getAssignable().isStatic()
321-
)
322-
}
323-
363+
/**
364+
* This is the local flow predicate that is used as a building block in global
365+
* data flow. It is a strict subset of the `localFlowStep` predicate, as it
366+
* excludes SSA flow through instance fields.
367+
*/
324368
cached
325-
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo, boolean simple) {
326-
any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo) and
327-
simple = true
328-
or
329-
// Flow from SSA definition to first read
330-
exists(Ssa::Definition def, ControlFlow::Node 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
334-
)
335-
or
336-
// Flow from read to next read
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
341-
|
342-
nodeFrom = TExprNode(cfnFrom)
343-
or
344-
cfnFrom = nodeFrom.(PostUpdateNode).getPreUpdateNode().getControlFlowNode()
369+
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
370+
exists(Ssa::Definition def |
371+
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
372+
not LocalFlow::usesInstanceField(def)
345373
)
346374
or
347-
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) and
348-
simple = true
349-
or
350-
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo) and
351-
simple = true
375+
any(LocalFlow::LocalExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo)
352376
or
353-
// Flow into SSA pseudo definition
354-
exists(Ssa::Definition def, Ssa::PseudoDefinition pseudo |
355-
LocalFlow::localFlowSsaInput(nodeFrom, def) and
356-
pseudo = nodeTo.(SsaDefinitionNode).getDefinition() and
357-
def = pseudo.getAnInput() and
358-
if usesInstanceField(def) then simple = false else simple = true
359-
)
377+
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo)
360378
or
361-
// Flow into uncertain SSA definition
362-
exists(Ssa::Definition def, LocalFlow::UncertainExplicitSsaDefinition uncertain |
363-
LocalFlow::localFlowSsaInput(nodeFrom, def) and
364-
uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and
365-
def = uncertain.getPriorDefinition() and
366-
if usesInstanceField(def) then simple = false else simple = true
367-
)
379+
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
368380
or
369-
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo) and
370-
simple = true
381+
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo)
371382
or
372-
flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true) and
373-
simple = true
383+
flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, true)
374384
or
375-
flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true) and
376-
simple = true
385+
flowThroughLibraryCallableOutRef(_, nodeFrom, nodeTo, true)
377386
or
378-
LocalFlow::localFlowStepCil(nodeFrom, nodeTo) and
379-
simple = true
387+
LocalFlow::localFlowStepCil(nodeFrom, nodeTo)
388+
}
389+
390+
/**
391+
* This is the extension of the predicate `simpleLocalFlowStep` that is exposed
392+
* as the `localFlowStep` predicate. It includes SSA flow through instance fields.
393+
*/
394+
cached
395+
predicate extendedLocalFlowStep(Node nodeFrom, Node nodeTo) {
396+
exists(Ssa::Definition def |
397+
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
398+
LocalFlow::usesInstanceField(def)
399+
)
380400
}
381401

382402
/**
@@ -424,15 +444,6 @@ private module Cached {
424444
}
425445
import Cached
426446

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-
436447
/** An SSA definition, viewed as a node in a data flow graph. */
437448
class SsaDefinitionNode extends Node, TSsaDefinitionNode {
438449
Ssa::Definition def;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ 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) { localFlowStepImpl(nodeFrom, nodeTo, _) }
155+
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
156+
simpleLocalFlowStep(nodeFrom, nodeTo)
157+
or
158+
extendedLocalFlowStep(nodeFrom, nodeTo)
159+
}
156160

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

0 commit comments

Comments
 (0)