Skip to content

Commit 20fab36

Browse files
committed
C#: Include "phi reads" in DataFlow::Node
1 parent 7a8c9e7 commit 20fab36

File tree

9 files changed

+536
-240
lines changed

9 files changed

+536
-240
lines changed

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

+12-26
Original file line numberDiff line numberDiff line change
@@ -138,25 +138,6 @@ module Ssa {
138138
}
139139
}
140140

141-
private string getSplitString(Definition def) {
142-
exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn |
143-
def.definesAt(_, bb, i) and
144-
result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString()
145-
|
146-
cfn = bb.getNode(i)
147-
or
148-
not exists(bb.getNode(i)) and
149-
cfn = bb.getFirstNode()
150-
)
151-
}
152-
153-
private string getToStringPrefix(Definition def) {
154-
result = "[" + getSplitString(def) + "] "
155-
or
156-
not exists(getSplitString(def)) and
157-
result = ""
158-
}
159-
160141
/**
161142
* A static single assignment (SSA) definition. Either an explicit variable
162143
* definition (`ExplicitDefinition`), an implicit variable definition
@@ -521,8 +502,8 @@ module Ssa {
521502

522503
override string toString() {
523504
if this.getADefinition() instanceof AssignableDefinitions::ImplicitParameterDefinition
524-
then result = getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")"
525-
else result = getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")"
505+
then result = SsaImpl::getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")"
506+
else result = SsaImpl::getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")"
526507
}
527508

528509
override Location getLocation() { result = ad.getLocation() }
@@ -570,8 +551,12 @@ module Ssa {
570551

571552
override string toString() {
572553
if this.getSourceVariable().getAssignable() instanceof LocalScopeVariable
573-
then result = getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")"
574-
else result = getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")"
554+
then
555+
result =
556+
SsaImpl::getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")"
557+
else
558+
result =
559+
SsaImpl::getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")"
575560
}
576561

577562
override Location getLocation() { result = this.getCallable().getLocation() }
@@ -612,7 +597,7 @@ module Ssa {
612597
}
613598

614599
override string toString() {
615-
result = getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")"
600+
result = SsaImpl::getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")"
616601
}
617602

618603
override Location getLocation() { result = this.getCall().getLocation() }
@@ -640,7 +625,8 @@ module Ssa {
640625
final Definition getQualifierDefinition() { result = q }
641626

642627
override string toString() {
643-
result = getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")"
628+
result =
629+
SsaImpl::getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")"
644630
}
645631

646632
override Location getLocation() { result = this.getQualifierDefinition().getLocation() }
@@ -682,7 +668,7 @@ module Ssa {
682668
}
683669

684670
override string toString() {
685-
result = getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")"
671+
result = SsaImpl::getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")"
686672
}
687673

688674
/*

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

+64-52
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, No
174174
cfn = n1.getControlFlowNode() and
175175
ssaDef.getADefinition() = def and
176176
ssaDef.getControlFlowNode() = cfnDef and
177-
n2.(SsaDefinitionNode).getDefinition() = ssaDef
177+
n2.(SsaDefinitionExtNode).getDefinitionExt() = ssaDef
178178
)
179179
}
180180

@@ -310,17 +310,20 @@ module LocalFlow {
310310
* Holds if `nodeFrom` is a last node referencing SSA definition `def`, which
311311
* can reach `next`.
312312
*/
313-
private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def, Ssa::Definition next) {
314-
exists(ControlFlow::BasicBlock bb, int i | SsaImpl::lastRefBeforeRedef(def, bb, i, next) |
315-
def.definesAt(_, bb, i) and
316-
def = getSsaDefinition(nodeFrom)
313+
private predicate localFlowSsaInput(
314+
Node nodeFrom, SsaImpl::DefinitionExt def, SsaImpl::DefinitionExt next
315+
) {
316+
exists(ControlFlow::BasicBlock bb, int i | SsaImpl::lastRefBeforeRedefExt(def, bb, i, next) |
317+
def.definesAt(_, bb, i, _) and
318+
def = getSsaDefinitionExt(nodeFrom)
317319
or
318-
nodeFrom.asExprAtNode(bb.getNode(i)) instanceof AssignableRead
320+
[nodeFrom, nodeFrom.(PostUpdateNode).getPreUpdateNode()].asExprAtNode(bb.getNode(i))
321+
instanceof AssignableRead
319322
)
320323
}
321324

322-
private Ssa::Definition getSsaDefinition(Node n) {
323-
result = n.(SsaDefinitionNode).getDefinition()
325+
private SsaImpl::DefinitionExt getSsaDefinitionExt(Node n) {
326+
result = n.(SsaDefinitionExtNode).getDefinitionExt()
324327
or
325328
result = n.(ExplicitParameterNode).getSsaDefinition()
326329
}
@@ -329,9 +332,9 @@ module LocalFlow {
329332
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
330333
* involving SSA definition `def`.
331334
*/
332-
predicate localSsaFlowStepUseUse(Ssa::Definition def, Node nodeFrom, Node nodeTo) {
335+
predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
333336
exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo |
334-
SsaImpl::adjacentReadPairSameVar(def, cfnFrom, cfnTo) and
337+
SsaImpl::adjacentReadPairSameVarExt(def, cfnFrom, cfnTo) and
335338
nodeTo = TExprNode(cfnTo) and
336339
nodeFrom = TExprNode(cfnFrom)
337340
)
@@ -341,35 +344,36 @@ module LocalFlow {
341344
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
342345
* SSA definition `def`.
343346
*/
344-
predicate localSsaFlowStep(Ssa::Definition def, Node nodeFrom, Node nodeTo) {
347+
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
345348
// Flow from SSA definition/parameter to first read
346-
exists(ControlFlow::Node cfn |
347-
def = getSsaDefinition(nodeFrom) and
348-
nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn)
349-
)
349+
def = getSsaDefinitionExt(nodeFrom) and
350+
SsaImpl::firstReadSameVarExt(def, nodeTo.(ExprNode).getControlFlowNode())
350351
or
351352
// Flow from read to next read
352353
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
353354
or
354-
// Flow into phi node
355-
exists(Ssa::PhiNode phi |
355+
// Flow into phi (read) node
356+
exists(SsaImpl::DefinitionExt phi |
356357
localFlowSsaInput(nodeFrom, def, phi) and
357-
phi = nodeTo.(SsaDefinitionNode).getDefinition() and
358-
def = phi.getAnInput()
358+
phi = nodeTo.(SsaDefinitionExtNode).getDefinitionExt()
359+
|
360+
phi instanceof Ssa::PhiNode
361+
or
362+
phi instanceof SsaImpl::PhiReadNode
359363
)
360364
or
361365
// Flow into uncertain SSA definition
362366
exists(LocalFlow::UncertainExplicitSsaDefinition uncertain |
363367
localFlowSsaInput(nodeFrom, def, uncertain) and
364-
uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and
368+
uncertain = nodeTo.(SsaDefinitionExtNode).getDefinitionExt() and
365369
def = uncertain.getPriorDefinition()
366370
)
367371
}
368372

369373
/**
370374
* Holds if the source variable of SSA definition `def` is an instance field.
371375
*/
372-
predicate usesInstanceField(Ssa::Definition def) {
376+
predicate usesInstanceField(SsaImpl::DefinitionExt def) {
373377
exists(Ssa::SourceVariables::FieldOrPropSourceVariable fp | fp = def.getSourceVariable() |
374378
not fp.getAssignable().(Modifiable).isStatic()
375379
)
@@ -378,7 +382,7 @@ module LocalFlow {
378382
predicate localFlowCapturedVarStep(Node nodeFrom, ImplicitCapturedArgumentNode nodeTo) {
379383
// Flow from SSA definition to implicit captured variable argument
380384
exists(Ssa::ExplicitDefinition def, ControlFlow::Nodes::ElementNode call |
381-
def = getSsaDefinition(nodeFrom) and
385+
def = getSsaDefinitionExt(nodeFrom) and
382386
def.isCapturedVariableDefinitionFlowIn(_, call, _) and
383387
nodeTo = TImplicitCapturedArgumentNode(call, def.getSourceVariable().getAssignable())
384388
)
@@ -455,7 +459,7 @@ module LocalFlow {
455459
}
456460

457461
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
458-
exists(Ssa::Definition def |
462+
exists(SsaImpl::DefinitionExt def |
459463
localSsaFlowStep(def, nodeFrom, nodeTo) and
460464
not usesInstanceField(def)
461465
)
@@ -517,7 +521,7 @@ module LocalFlow {
517521
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
518522
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
519523
or
520-
exists(Ssa::Definition def |
524+
exists(SsaImpl::DefinitionExt def |
521525
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
522526
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom,
523527
any(DataFlowSummarizedCallable sc)) and
@@ -788,7 +792,7 @@ private module Cached {
788792
} or
789793
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
790794
TCilSsaDefinitionNode(CilSsa::Definition def) or
791-
TSsaDefinitionNode(Ssa::Definition def) {
795+
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
792796
// Handled by `TExplicitParameterNode` below
793797
not def.(Ssa::ExplicitDefinition).getADefinition() instanceof
794798
AssignableDefinitions::ImplicitParameterDefinition
@@ -854,7 +858,7 @@ private module Cached {
854858
or
855859
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
856860
or
857-
exists(Ssa::Definition def |
861+
exists(SsaImpl::DefinitionExt def |
858862
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
859863
LocalFlow::usesInstanceField(def)
860864
)
@@ -904,9 +908,11 @@ import Cached
904908

905909
/** Holds if `n` should be hidden from path explanations. */
906910
predicate nodeIsHidden(Node n) {
907-
exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() |
911+
exists(SsaImpl::DefinitionExt def | def = n.(SsaDefinitionExtNode).getDefinitionExt() |
908912
def instanceof Ssa::PhiNode
909913
or
914+
def instanceof SsaImpl::PhiReadNode
915+
or
910916
def instanceof Ssa::ImplicitEntryDefinition
911917
or
912918
def instanceof Ssa::ImplicitCallDefinition
@@ -959,23 +965,31 @@ class CilSsaDefinitionNode extends NodeImpl, TCilSsaDefinitionNode {
959965
}
960966

961967
/** An SSA definition, viewed as a node in a data flow graph. */
962-
class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
963-
Ssa::Definition def;
968+
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
969+
SsaImpl::DefinitionExt def;
964970

965-
SsaDefinitionNode() { this = TSsaDefinitionNode(def) }
971+
SsaDefinitionExtNode() { this = TSsaDefinitionExtNode(def) }
966972

967973
/** Gets the underlying SSA definition. */
968-
Ssa::Definition getDefinition() { result = def }
974+
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
969975

970976
override DataFlowCallable getEnclosingCallableImpl() {
971-
result.asCallable() = def.getEnclosingCallable()
977+
result.asCallable() = def.(Ssa::Definition).getEnclosingCallable()
978+
or
979+
result.asCallable() = def.(SsaImpl::PhiReadNode).getSourceVariable().getEnclosingCallable()
972980
}
973981

974982
override Type getTypeImpl() { result = def.getSourceVariable().getType() }
975983

976-
override ControlFlow::Node getControlFlowNodeImpl() { result = def.getControlFlowNode() }
984+
override ControlFlow::Node getControlFlowNodeImpl() {
985+
result = def.(Ssa::Definition).getControlFlowNode()
986+
}
977987

978-
override Location getLocationImpl() { result = def.getLocation() }
988+
override Location getLocationImpl() {
989+
result = def.(Ssa::Definition).getLocation()
990+
or
991+
result = def.(SsaImpl::PhiReadNode).getBasicBlock().getLocation()
992+
}
979993

980994
override string toStringImpl() { result = def.toString() }
981995
}
@@ -1067,13 +1081,11 @@ private module ParameterNodes {
10671081
* } }
10681082
* ```
10691083
*/
1070-
class ImplicitCapturedParameterNode extends ParameterNodeImpl, SsaDefinitionNode {
1071-
override SsaCapturedEntryDefinition def;
1072-
1073-
ImplicitCapturedParameterNode() { def = this.getDefinition() }
1084+
class ImplicitCapturedParameterNode extends ParameterNodeImpl, SsaDefinitionExtNode {
1085+
ImplicitCapturedParameterNode() { def instanceof SsaCapturedEntryDefinition }
10741086

10751087
/** Gets the captured variable that this implicit parameter models. */
1076-
LocalScopeVariable getVariable() { result = def.getVariable() }
1088+
LocalScopeVariable getVariable() { result = def.(SsaCapturedEntryDefinition).getVariable() }
10771089

10781090
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
10791091
pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and
@@ -1308,12 +1320,12 @@ private module ReturnNodes {
13081320
* A data-flow node that represents an assignment to an `out` or a `ref`
13091321
* parameter.
13101322
*/
1311-
class OutRefReturnNode extends ReturnNode, SsaDefinitionNode {
1323+
class OutRefReturnNode extends ReturnNode, SsaDefinitionExtNode {
13121324
OutRefReturnKind kind;
13131325

13141326
OutRefReturnNode() {
13151327
exists(Parameter p |
1316-
this.getDefinition().isLiveOutRefParameterDefinition(p) and
1328+
this.getDefinitionExt().(Ssa::Definition).isLiveOutRefParameterDefinition(p) and
13171329
kind.getPosition() = p.getPosition()
13181330
|
13191331
p.isOut() and kind instanceof OutReturnKind
@@ -1397,20 +1409,20 @@ private module ReturnNodes {
13971409
* } }
13981410
* ```
13991411
*/
1400-
class ImplicitCapturedReturnNode extends ReturnNode, SsaDefinitionNode {
1412+
class ImplicitCapturedReturnNode extends ReturnNode, SsaDefinitionExtNode {
14011413
private Ssa::ExplicitDefinition edef;
14021414

14031415
ImplicitCapturedReturnNode() {
1404-
edef = this.getDefinition() and
1416+
edef = this.getDefinitionExt() and
14051417
edef.isCapturedVariableDefinitionFlowOut(_, _)
14061418
}
14071419

14081420
/**
14091421
* Holds if the value at this node may flow out to the implicit call definition
14101422
* at `node`, using one or more calls.
14111423
*/
1412-
predicate flowsOutTo(SsaDefinitionNode node, boolean additionalCalls) {
1413-
edef.isCapturedVariableDefinitionFlowOut(node.getDefinition(), additionalCalls)
1424+
predicate flowsOutTo(SsaDefinitionExtNode node, boolean additionalCalls) {
1425+
edef.isCapturedVariableDefinitionFlowOut(node.getDefinitionExt(), additionalCalls)
14141426
}
14151427

14161428
override ImplicitCapturedReturnKind getKind() {
@@ -1517,13 +1529,13 @@ private module OutNodes {
15171529
* A data-flow node that reads a value returned implicitly by a callable
15181530
* using a captured variable.
15191531
*/
1520-
class CapturedOutNode extends OutNode, SsaDefinitionNode {
1532+
class CapturedOutNode extends OutNode, SsaDefinitionExtNode {
15211533
private DataFlowCall call;
15221534

15231535
CapturedOutNode() {
15241536
exists(ImplicitCapturedReturnNode n, boolean additionalCalls, ControlFlow::Node cfn |
15251537
n.flowsOutTo(this, additionalCalls) and
1526-
cfn = this.getDefinition().getControlFlowNode()
1538+
cfn = this.getDefinitionExt().(Ssa::Definition).getControlFlowNode()
15271539
|
15281540
additionalCalls = false and call = csharpCall(_, cfn)
15291541
or
@@ -1535,7 +1547,7 @@ private module OutNodes {
15351547
override DataFlowCall getCall(ReturnKind kind) {
15361548
result = call and
15371549
kind.(ImplicitCapturedReturnKind).getVariable() =
1538-
this.getDefinition().getSourceVariable().getAssignable()
1550+
this.getDefinitionExt().getSourceVariable().getAssignable()
15391551
}
15401552
}
15411553

@@ -1816,7 +1828,7 @@ predicate readStep(Node node1, Content c, Node node2) {
18161828
exists(ForeachStmt fs, Ssa::ExplicitDefinition def |
18171829
x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(),
18181830
def.getControlFlowNode()) and
1819-
node2.(SsaDefinitionNode).getDefinition() = def and
1831+
node2.(SsaDefinitionExtNode).getDefinitionExt() = def and
18201832
c instanceof ElementContent
18211833
)
18221834
or
@@ -1839,7 +1851,7 @@ predicate readStep(Node node1, Content c, Node node2) {
18391851
or
18401852
// item = variable in node1 = (..., variable, ...)
18411853
exists(AssignableDefinitions::TupleAssignmentDefinition tad, Ssa::ExplicitDefinition def |
1842-
node2.(SsaDefinitionNode).getDefinition() = def and
1854+
node2.(SsaDefinitionExtNode).getDefinitionExt() = def and
18431855
def.getADefinition() = tad and
18441856
tad.getLeaf() = item and
18451857
hasNodePath(x, node1, node2)
@@ -1848,7 +1860,7 @@ predicate readStep(Node node1, Content c, Node node2) {
18481860
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
18491861
te = any(PatternExpr pe).getAChildExpr*() and
18501862
exists(AssignableDefinitions::LocalVariableDefinition lvd, Ssa::ExplicitDefinition def |
1851-
node2.(SsaDefinitionNode).getDefinition() = def and
1863+
node2.(SsaDefinitionExtNode).getDefinitionExt() = def and
18521864
def.getADefinition() = lvd and
18531865
lvd.getDeclaration() = item and
18541866
hasNodePath(x, node1, node2)
@@ -2182,7 +2194,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
21822194

21832195
/** Extra data-flow steps needed for lambda flow analysis. */
21842196
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
2185-
exists(Ssa::Definition def |
2197+
exists(SsaImpl::DefinitionExt def |
21862198
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo) and
21872199
LocalFlow::usesInstanceField(def) and
21882200
preservesValue = true

0 commit comments

Comments
 (0)