Skip to content

Commit cf860f1

Browse files
authored
Merge pull request #5071 from hvitved/csharp/ssa/uncertain-reads
C#: Move uncertain-read logic into shared SSA implementation
2 parents 40d02e7 + b19fd7b commit cf860f1

File tree

4 files changed

+164
-130
lines changed

4 files changed

+164
-130
lines changed

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,18 @@ module Ssa {
384384
result.getAControlFlowNode() = cfn
385385
}
386386

387+
/**
388+
* Gets an SSA definition whose value can flow to this one in one step. This
389+
* includes inputs to phi nodes and the prior definitions of uncertain writes.
390+
*/
391+
private Definition getAPhiInputOrPriorDefinition() {
392+
result = this.(PhiNode).getAnInput() or
393+
result = this.(UncertainDefinition).getPriorDefinition()
394+
}
395+
387396
/**
388397
* Gets a definition that ultimately defines this SSA definition and is
389-
* not itself a pseudo node. Example:
398+
* not itself a phi node. Example:
390399
*
391400
* ```csharp
392401
* int Field;
@@ -413,8 +422,9 @@ module Ssa {
413422
* definition on line 4, the explicit definition on line 7, and the implicit
414423
* definition on line 9.
415424
*/
416-
final override Definition getAnUltimateDefinition() {
417-
result = SsaImpl::Definition.super.getAnUltimateDefinition()
425+
final Definition getAnUltimateDefinition() {
426+
result = this.getAPhiInputOrPriorDefinition*() and
427+
not result instanceof PhiNode
418428
}
419429

420430
/**
@@ -425,7 +435,7 @@ module Ssa {
425435
/**
426436
* Gets the syntax element associated with this SSA definition, if any.
427437
* This is either an expression, for example `x = 0`, a parameter, or a
428-
* callable. Pseudo nodes have no associated syntax element.
438+
* callable. Phi nodes have no associated syntax element.
429439
*/
430440
Element getElement() { result = this.getControlFlowNode().getElement() }
431441

@@ -681,7 +691,12 @@ module Ssa {
681691
* definition on line 4, the explicit definition on line 7, and the implicit
682692
* call definition on line 9 as inputs.
683693
*/
684-
final override Definition getAnInput() { result = SsaImpl::PhiNode.super.getAnInput() }
694+
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
695+
696+
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
697+
predicate hasInputFromBlock(Definition inp, ControlFlow::BasicBlock bb) {
698+
inp = SsaImpl::phiHasInputFromBlock(this, bb)
699+
}
685700

686701
override string toString() {
687702
result = getToStringPrefix(this) + "SSA phi(" + getSourceVariable() + ")"
@@ -704,5 +719,11 @@ module Ssa {
704719
* need not be certain), an implicit non-local update via a call, or an
705720
* uncertain update of the qualifier.
706721
*/
707-
class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition { }
722+
class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition {
723+
/**
724+
* Gets the immediately preceding definition. Since this update is uncertain,
725+
* the value from the preceding definition might still be valid.
726+
*/
727+
Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) }
728+
}
708729
}

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

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -954,10 +954,12 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou
954954
*
955955
* This includes implicit reads via calls.
956956
*/
957-
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) {
958-
variableReadActual(bb, i, v)
957+
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
958+
variableReadActual(bb, i, v) and
959+
certain = true
959960
or
960-
variableReadPseudo(bb, i, v)
961+
variableReadPseudo(bb, i, v) and
962+
certain = false
961963
}
962964

963965
cached
@@ -1073,7 +1075,7 @@ private module Cached {
10731075
Ssa::ExplicitDefinition def, Ssa::ImplicitEntryDefinition edef,
10741076
ControlFlow::Nodes::ElementNode c, boolean additionalCalls
10751077
) {
1076-
exists(Ssa::SourceVariable v, Definition def0, ControlFlow::BasicBlock bb, int i |
1078+
exists(Ssa::SourceVariable v, Ssa::Definition def0, ControlFlow::BasicBlock bb, int i |
10771079
v = def.getSourceVariable() and
10781080
capturedReadIn(_, _, v, edef.getSourceVariable(), c, additionalCalls) and
10791081
def = def0.getAnUltimateDefinition() and
@@ -1107,24 +1109,9 @@ private module Cached {
11071109
ssaDefReachesEndOfBlock(bb, def, _)
11081110
}
11091111

1110-
private predicate adjacentDefReaches(
1111-
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2
1112-
) {
1113-
adjacentDefRead(def, bb1, i1, bb2, i2)
1114-
or
1115-
exists(ControlFlow::BasicBlock bb3, int i3 |
1116-
adjacentDefReaches(def, bb1, i1, bb3, i3) and
1117-
variableReadPseudo(bb3, i3, _) and
1118-
adjacentDefRead(def, bb3, i3, bb2, i2)
1119-
)
1120-
}
1121-
1122-
pragma[noinline]
1123-
private predicate adjacentDefActualRead(
1124-
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2
1125-
) {
1126-
adjacentDefReaches(def, bb1, i1, bb2, i2) and
1127-
variableReadActual(bb2, i2, _)
1112+
cached
1113+
Definition phiHasInputFromBlock(PhiNode phi, ControlFlow::BasicBlock bb) {
1114+
phiHasInputFromBlock(phi, result, bb)
11281115
}
11291116

11301117
cached
@@ -1145,7 +1132,7 @@ private module Cached {
11451132
predicate firstReadSameVar(Definition def, ControlFlow::Node cfn) {
11461133
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
11471134
def.definesAt(_, bb1, i1) and
1148-
adjacentDefActualRead(def, bb1, i1, bb2, i2) and
1135+
adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and
11491136
cfn = bb2.getNode(i2)
11501137
)
11511138
}
@@ -1160,53 +1147,30 @@ private module Cached {
11601147
exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 |
11611148
cfn1 = bb1.getNode(i1) and
11621149
variableReadActual(bb1, i1, _) and
1163-
adjacentDefActualRead(def, bb1, i1, bb2, i2) and
1150+
adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and
11641151
cfn2 = bb2.getNode(i2)
11651152
)
11661153
}
11671154

1168-
private predicate adjacentDefPseudoRead(
1169-
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2
1170-
) {
1171-
adjacentDefReaches(def, bb1, i1, bb2, i2) and
1172-
variableReadPseudo(bb2, i2, _)
1173-
}
1174-
1175-
private predicate reachesLastRefRedef(
1176-
Definition def, ControlFlow::BasicBlock bb, int i, Definition next
1177-
) {
1178-
lastRefRedef(def, bb, i, next)
1179-
or
1180-
exists(ControlFlow::BasicBlock bb0, int i0 |
1181-
reachesLastRefRedef(def, bb0, i0, next) and
1182-
adjacentDefPseudoRead(def, bb, i, bb0, i0)
1183-
)
1184-
}
1185-
11861155
cached
11871156
predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) {
1188-
reachesLastRefRedef(def, bb, i, next) and
1189-
not variableReadPseudo(bb, i, def.getSourceVariable())
1190-
}
1191-
1192-
private predicate reachesLastRef(Definition def, ControlFlow::BasicBlock bb, int i) {
1193-
lastRef(def, bb, i)
1194-
or
1195-
exists(ControlFlow::BasicBlock bb0, int i0 |
1196-
reachesLastRef(def, bb0, i0) and
1197-
adjacentDefPseudoRead(def, bb, i, bb0, i0)
1198-
)
1157+
lastRefRedefNoUncertainReads(def, bb, i, next)
11991158
}
12001159

12011160
cached
12021161
predicate lastReadSameVar(Definition def, ControlFlow::Node cfn) {
12031162
exists(ControlFlow::BasicBlock bb, int i |
1204-
reachesLastRef(def, bb, i) and
1163+
lastRefNoUncertainReads(def, bb, i) and
12051164
variableReadActual(bb, i, _) and
12061165
cfn = bb.getNode(i)
12071166
)
12081167
}
12091168

1169+
cached
1170+
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
1171+
uncertainWriteDefinitionInput(def, result)
1172+
}
1173+
12101174
cached
12111175
predicate isLiveOutRefParameterDefinition(Ssa::Definition def, Parameter p) {
12121176
p.isOutOrRef() and

0 commit comments

Comments
 (0)