Skip to content

Commit

Permalink
Java: Rework adjacentUseUse
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Jul 9, 2024
1 parent 1a39f30 commit 132d68c
Showing 1 changed file with 67 additions and 97 deletions.
164 changes: 67 additions & 97 deletions java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,6 @@ private ControlFlowNode captureNode(TrackedVar capturedvar, TrackedVar closureva
)
}

/** Holds if `VarAccess` `use` of `v` occurs in `b` at index `i`. */
private predicate variableUse(TrackedVar v, VarRead use, BasicBlock b, int i) {
v.getAnAccess() = use and b.getNode(i) = use
}

/** Holds if the value of `v` is captured in `b` at index `i`. */
private predicate variableCapture(TrackedVar capturedvar, TrackedVar closurevar, BasicBlock b, int i) {
b.getNode(i) = captureNode(capturedvar, closurevar)
Expand Down Expand Up @@ -177,66 +172,6 @@ class UntrackedDef extends Definition {
Location getLocation() { result = read.getLocation() }
}

pragma[noinline]
private predicate adjacentDefRead(
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
SsaInput::SourceVariable v
) {
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}

pragma[nomagic]
predicate adjacentDefReachesRead(
Definition def, SsaInput::SourceVariable v, SsaInput::BasicBlock bb1, int i1,
SsaInput::BasicBlock bb2, int i2
) {
adjacentDefRead(def, bb1, i1, bb2, i2, v) and
(
def.definesAt(v, bb1, i1)
or
SsaInput::variableRead(bb1, i1, v, true)
)
or
exists(SsaInput::BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, v, bb1, i1, bb3, i3) and
SsaInput::variableRead(bb3, i3, _, false) and
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
)
}

/** Same as `adjacentDefRead`, but skips uncertain reads. */
pragma[nomagic]
private predicate adjacentDefSkipUncertainReads(
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesRead(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, true)
)
}

pragma[nomagic]
private predicate adjacentDefReachesUncertainRead(
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
) {
exists(SsaInput::SourceVariable v |
adjacentDefReachesRead(def, v, bb1, i1, bb2, i2) and
SsaInput::variableRead(bb2, i2, v, false)
)
}

pragma[nomagic]
predicate lastRefBeforeRedef(Definition def, BasicBlock bb, int i, Definition next) {
Impl::lastRefRedef(def, bb, i, next) and
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
or
exists(SsaInput::BasicBlock bb0, int i0 |
Impl::lastRefRedef(def, bb0, i0, next) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}

cached
private module Cached {
cached
Expand Down Expand Up @@ -556,12 +491,27 @@ private module Cached {
)
}

pragma[nomagic]
private predicate captureDefReaches(Definition def, SsaInput::BasicBlock bb2, int i2) {
variableCapture(def.getSourceVariable(), _, _, _) and
exists(SsaInput::BasicBlock bb1, int i1 |
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
def.definesAt(_, bb1, i1)
)
or
exists(SsaInput::BasicBlock bb3, int i3 |
captureDefReaches(def, bb3, i3) and
SsaInput::variableRead(bb3, i3, _, _) and
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
)
}

/** Holds if `init` is a closure variable that captures the value of `capturedvar`. */
cached
predicate captures(SsaImplicitInit init, SsaVariable capturedvar) {
exists(BasicBlock bb2, int i2 |
adjacentDefReachesRead(capturedvar, _, _, _, bb2, i2) and
variableCapture(capturedvar.getSourceVariable(), init.getSourceVariable(), bb2, i2)
exists(BasicBlock bb, int i |
captureDefReaches(capturedvar, bb, i) and
variableCapture(capturedvar.getSourceVariable(), init.getSourceVariable(), bb, i)
)
}

Expand All @@ -574,16 +524,22 @@ private module Cached {
Impl::uncertainWriteDefinitionInput(redef, def)
}

/**
* Holds if the value defined at SSA definition `def` can reach a read at `use`,
* without passing through any other read.
*/
pragma[nomagic]
private predicate firstUseSameVar(Definition def, VarRead use) {
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
def.definesAt(_, bb1, i1) and
adjacentDefSkipUncertainReads(def, bb1, i1, bb2, i2) and
use = bb2.getNode(i2)
private predicate defReaches(Definition def, DataFlowIntegration::Node node) {
exists(DataFlowIntegration::SsaDefinitionExtNode nodeFrom |
nodeFrom.getDefinitionExt() = def and
DataFlowIntegrationImpl::localFlowStep(_, nodeFrom, node, false)
)
or
exists(DataFlowIntegration::Node mid |
defReaches(def, mid) and
DataFlowIntegrationImpl::localFlowStep(_, mid, node, _)
|
// flow into phi input node
mid instanceof DataFlowIntegration::SsaInputNode
or
// flow into definition
mid instanceof DataFlowIntegration::SsaDefinitionExtNode
)
}

Expand All @@ -593,14 +549,9 @@ private module Cached {
*/
cached
predicate firstUse(Definition def, VarRead use) {
firstUseSameVar(def, use)
or
exists(Definition redef, BasicBlock b1, int i1 |
redef instanceof SsaUncertainImplicitUpdate or redef instanceof SsaPhiNode
|
lastRefBeforeRedef(def, b1, i1, redef) and
def.definesAt(_, b1, i1) and
firstUse(redef, use)
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use and
defReaches(def, nodeTo)
)
}

Expand Down Expand Up @@ -646,17 +597,41 @@ private module Cached {

cached
module SsaPublic {
pragma[nomagic]
private predicate useReaches(VarRead use, DataFlowIntegration::Node node, boolean sameVar) {
exists(DataFlowIntegration::ExprNode nodeFrom |
nodeFrom.getExpr() = use and
DataFlowIntegration::localFlowStep(_, nodeFrom, node, true) and
sameVar = true
)
or
exists(DataFlowIntegration::Node mid, boolean sameVarMid |
useReaches(use, mid, sameVarMid) and
DataFlowIntegration::localFlowStep(_, mid, node, _)
|
// flow into phi input node
mid instanceof DataFlowIntegration::SsaInputNode and
sameVar = false
or
// flow into definition
exists(Impl::DefinitionExt def |
def = mid.(DataFlowIntegration::SsaDefinitionExtNode).getDefinitionExt()
|
if def instanceof Impl::PhiReadNode then sameVar = sameVarMid else sameVar = false
)
)
}

/**
* Holds if `use1` and `use2` form an adjacent use-use-pair of the same SSA
* variable, that is, the value read in `use1` can reach `use2` without passing
* through any other use or any SSA definition of the variable.
*/
cached
predicate adjacentUseUseSameVar(VarRead use1, VarRead use2) {
exists(TrackedVar v, BasicBlock b1, int i1, BasicBlock b2, int i2 |
adjacentDefSkipUncertainReads(_, b1, i1, b2, i2) and
variableUse(v, use1, b1, i1) and
variableUse(v, use2, b2, i2)
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use2 and
useReaches(use1, nodeTo, true)
)
}

Expand All @@ -668,14 +643,9 @@ private module Cached {
*/
cached
predicate adjacentUseUse(VarRead use1, VarRead use2) {
adjacentUseUseSameVar(use1, use2)
or
exists(TrackedSsaDef def, BasicBlock b1, int i1 |
lastRefBeforeRedef(_, b1, i1, def) and
variableUse(_, use1, b1, i1) and
firstUse(def, use2)
|
def instanceof SsaUncertainImplicitUpdate or def instanceof SsaPhiNode
exists(DataFlowIntegration::ExprNode nodeTo |
nodeTo.getExpr() = use2 and
useReaches(use1, nodeTo, _)
)
}
}
Expand Down

0 comments on commit 132d68c

Please sign in to comment.