Skip to content

Commit 06df5c0

Browse files
committed
Java: Introduce SsaCapturedDefinition and replace uses of getAnUltimateDefinition.
1 parent 483b2d8 commit 06df5c0

File tree

10 files changed

+64
-24
lines changed

10 files changed

+64
-24
lines changed

java/ql/lib/semmle/code/java/dataflow/DefUse.qll

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ predicate useUsePair(VarRead use1, VarRead use2) { adjacentUseUse+(use1, use2) }
3434
* Other paths may also exist, so the SSA variables in `def` and `use` can be different.
3535
*/
3636
predicate defUsePair(VariableUpdate def, VarRead use) {
37-
exists(SsaVariable v |
38-
v.getAUse() = use and v.getAnUltimateDefinition().(SsaExplicitWrite).getDefiningExpr() = def
37+
exists(SsaDefinition v, SsaExplicitWrite write |
38+
v.getARead() = use and write.getDefiningExpr() = def
39+
|
40+
v.getAnUltimateDefinition() = write
41+
or
42+
v.(SsaCapturedDefinition).getAnUltimateCapturedDefinition() = write
3943
)
4044
}
4145

@@ -46,7 +50,9 @@ predicate defUsePair(VariableUpdate def, VarRead use) {
4650
* Other paths may also exist, so the SSA variables can be different.
4751
*/
4852
predicate parameterDefUsePair(Parameter p, VarRead use) {
49-
exists(SsaVariable v |
50-
v.getAUse() = use and v.getAnUltimateDefinition().(SsaParameterInit).getParameter() = p
53+
exists(SsaDefinition v, SsaParameterInit init | v.getARead() = use and init.getParameter() = p |
54+
v.getAnUltimateDefinition() = init
55+
or
56+
v.(SsaCapturedDefinition).getAnUltimateCapturedDefinition() = init
5157
)
5258
}

java/ql/lib/semmle/code/java/dataflow/NullGuards.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ predicate clearlyNotNull(SsaVariable v, Expr reason) {
120120
reason = decl
121121
)
122122
or
123-
exists(SsaVariable captured |
124-
v.(SsaImplicitInit).captures(captured) and
123+
exists(SsaDefinition captured |
124+
v.(SsaCapturedDefinition).captures(captured) and
125125
clearlyNotNull(captured, reason)
126126
)
127127
or

java/ql/lib/semmle/code/java/dataflow/Nullness.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ predicate nullDeref(SsaSourceVariable v, VarAccess va, string msg, Expr reason)
278278
* A dereference of a variable that is always `null`.
279279
*/
280280
predicate alwaysNullDeref(SsaSourceVariable v, VarAccess va) {
281-
exists(BasicBlock bb, SsaVariable ssa |
282-
forall(SsaVariable def | def = ssa.getAnUltimateDefinition() |
281+
exists(BasicBlock bb, SsaDefinition ssa |
282+
forall(SsaDefinition def | def = ssa.getAnUltimateDefinition() |
283283
def.(SsaExplicitWrite).getValue() = alwaysNullExpr()
284284
)
285285
or

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

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ class SsaSourceField extends SsaSourceVariable {
140140
}
141141
}
142142

143+
/** An SSA definition in a closure that captures a variable. */
144+
class SsaCapturedDefinition extends SsaImplicitEntryDefinition {
145+
SsaCapturedDefinition() { captures(this, _) }
146+
147+
override string toString() { result = "SSA capture def(" + this.getSourceVariable() + ")" }
148+
149+
/** Holds if this definition captures the value of `capturedvar`. */
150+
predicate captures(SsaDefinition capturedvar) { captures(this, capturedvar) }
151+
152+
/**
153+
* Gets a definition that ultimately defines the captured variable and is not itself a phi node.
154+
*/
155+
SsaDefinition getAnUltimateCapturedDefinition() {
156+
exists(SsaDefinition capturedvar |
157+
captures(this, capturedvar) and result = capturedvar.getAnUltimateDefinition()
158+
)
159+
}
160+
}
161+
143162
/**
144163
* Gets an access of the SSA source variable underlying this SSA variable
145164
* that can be reached from this SSA variable without passing through any
@@ -194,18 +213,25 @@ class SsaVariable extends Definition {
194213
predicate isLiveAtEndOfBlock(BasicBlock b) { ssaDefReachesEndOfBlock(b, this) }
195214

196215
/**
216+
* DEPRECATED.
217+
*
197218
* Gets an SSA variable whose value can flow to this one in one step. This
198219
* includes inputs to phi nodes, the prior definition of uncertain updates,
199220
* and the captured ssa variable for a closure variable.
200221
*/
201-
SsaVariable getAPhiInputOrPriorDef() {
222+
deprecated SsaVariable getAPhiInputOrPriorDef() {
202223
result = this.(SsaPhiNode).getAPhiInput() or
203224
result = this.(SsaUncertainImplicitUpdate).getPriorDef() or
204225
this.(SsaImplicitInit).captures(result)
205226
}
206227

207-
/** Gets a definition that ultimately defines this variable and is not itself a phi node. */
208-
SsaVariable getAnUltimateDefinition() {
228+
/**
229+
* DEPRECATED: Use `SsaCapturedDefinition::getAnUltimateCapturedDefinition()`
230+
* and/or `SsaDefinition::getAnUltimateDefinition()` instead.
231+
*
232+
* Gets a definition that ultimately defines this variable and is not itself a phi node.
233+
*/
234+
deprecated SsaVariable getAnUltimateDefinition() {
209235
result = this.getAPhiInputOrPriorDef*() and not result instanceof SsaPhiNode
210236
}
211237
}
@@ -319,6 +345,8 @@ class SsaUncertainImplicitUpdate extends SsaImplicitUpdate {
319345
}
320346

321347
/**
348+
* DEPRECATED: Use `SsaParameterInit`, `SsaImplicitEntryDefinition`, or `SsaCapturedDefinition` instead.
349+
*
322350
* An SSA variable that is defined by its initial value in the callable. This
323351
* includes initial values of parameters, fields, and closure variables.
324352
*/

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ private predicate fieldStep(Node node1, Node node2) {
6262
private predicate closureFlowStep(Expr e1, Expr e2) {
6363
simpleAstFlowStep(e1, e2)
6464
or
65-
exists(SsaVariable v |
66-
v.getAUse() = e2 and
67-
v.getAnUltimateDefinition().(SsaExplicitWrite).getValue() = e1
65+
exists(SsaDefinition v, SsaExplicitWrite def | v.getARead() = e2 and def.getValue() = e1 |
66+
v.getAnUltimateDefinition() = def
67+
or
68+
v.(SsaCapturedDefinition).getAnUltimateCapturedDefinition() = def
6869
)
6970
}
7071

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)
101101
predicate hasNonlocalValue(FieldRead fr) {
102102
not exists(SsaVariable v | v.getAUse() = fr)
103103
or
104-
exists(SsaVariable v, SsaVariable def | v.getAUse() = fr and def = v.getAnUltimateDefinition() |
104+
exists(SsaDefinition v, SsaDefinition def |
105+
v.getARead() = fr and def = v.getAnUltimateDefinition()
106+
|
105107
def instanceof SsaImplicitInit or
106108
def instanceof SsaImplicitUpdate
107109
)

java/ql/lib/semmle/code/java/frameworks/InputStream.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ private class InputStreamWrapperCapturedJumpStep extends AdditionalTaintStep {
4141
*/
4242
private class InputStreamWrapperCapturedLocalStep extends AdditionalTaintStep {
4343
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
44-
exists(InputStreamRead m, NestedClass wrapper, SsaVariable captured, SsaImplicitInit capturer |
44+
exists(
45+
InputStreamRead m, NestedClass wrapper, SsaDefinition captured, SsaCapturedDefinition capturer
46+
|
4547
wrapper.getASourceSupertype+() instanceof TypeInputStream and
4648
m.getDeclaringType() = wrapper and
4749
capturer.captures(captured) and

java/ql/lib/semmle/code/java/security/CommandArguments.qll

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ private predicate isShell(Expr ex) {
3838
cmd.regexpMatch(".*(sh|javac?|python[23]?|osascript|cmd)(\\.exe)?$")
3939
)
4040
or
41-
exists(SsaVariable ssa |
42-
ex = ssa.getAUse() and
43-
isShell(ssa.getAnUltimateDefinition().(SsaExplicitWrite).getDefiningExpr())
41+
exists(SsaDefinition ssa, SsaExplicitWrite def |
42+
ex = ssa.getARead() and
43+
isShell(def.getDefiningExpr())
44+
|
45+
ssa.getAnUltimateDefinition() = def
46+
or
47+
ssa.(SsaCapturedDefinition).getAnUltimateCapturedDefinition() = def
4448
)
4549
or
4650
isShell(ex.(Assignment).getRhs())

java/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
277277

278278
predicate sinkModelSanitizer(DataFlow::Node node) {
279279
// exclude variable capture jump steps
280-
exists(Ssa::SsaImplicitInit closure |
281-
closure.captures(_) and
282-
node.asExpr() = Ssa::ssaGetAFirstUse(closure)
283-
)
280+
exists(Ssa::SsaCapturedDefinition closure | node.asExpr() = Ssa::ssaGetAFirstUse(closure))
284281
}
285282

286283
predicate apiSource(DataFlow::Node source) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import java
22
import semmle.code.java.dataflow.SSA
33

4-
from SsaImplicitInit closure, SsaVariable captured
4+
from SsaCapturedDefinition closure, SsaDefinition captured
55
where closure.captures(captured)
66
select closure, captured

0 commit comments

Comments
 (0)