mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #2099 from aschackmull/java/callcontext-bool-pruning
Java: Data-flow pruning based on call contexts.
This commit is contained in:
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -120,13 +120,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -152,7 +155,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -164,7 +167,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,14 +183,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,6 +225,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -462,13 +468,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -494,7 +503,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -506,7 +515,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -522,14 +531,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -562,6 +573,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -575,11 +587,22 @@ private module ImplCommon {
|
||||
exists(ArgumentNode arg | arg.argumentOf(call, -1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TCallContext =
|
||||
TAnyCallContext() or
|
||||
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
|
||||
reducedViableImplInCallContext(_, _, call) and
|
||||
recordDataFlowCallSite(call, _) and
|
||||
(emptyAp = true or emptyAp = false) and
|
||||
(
|
||||
exists(call.getArgument(i))
|
||||
@@ -593,6 +616,11 @@ private module ImplCommon {
|
||||
cached
|
||||
newtype TReturnPosition =
|
||||
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
|
||||
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -602,14 +630,15 @@ private module ImplCommon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context to restrict the targets of virtual dispatch and match the
|
||||
* call sites of flow into a method with flow out of a method.
|
||||
* A call context to restrict the targets of virtual dispatch, prune local flow,
|
||||
* and match the call sites of flow into a method with flow out of a method.
|
||||
*
|
||||
* There are four cases:
|
||||
* - `TAnyCallContext()` : No restrictions on method flow.
|
||||
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
|
||||
* parameter at the given `call`. This call improves the set of viable
|
||||
* dispatch targets for at least one method call in the current callable.
|
||||
* dispatch targets for at least one method call in the current callable
|
||||
* or helps prune unreachable nodes in the current callable.
|
||||
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
|
||||
* originating call does not improve the set of dispatch targets for any
|
||||
* method call in the current callable and was therefore not recorded.
|
||||
@@ -619,10 +648,15 @@ private module ImplCommon {
|
||||
*/
|
||||
abstract class CallContext extends TCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
@@ -633,16 +667,73 @@ private module ImplCommon {
|
||||
result = "CcCall(" + call + ", " + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
|
||||
}
|
||||
|
||||
class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context that is relevant for pruning local flow.
|
||||
*/
|
||||
abstract class LocalCallContext extends TLocalFlowCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class LocalCallContextAny extends LocalCallContext, TAnyLocalCall {
|
||||
override string toString() { result = "LocalCcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall {
|
||||
LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) }
|
||||
|
||||
DataFlowCall call;
|
||||
|
||||
DataFlowCall getCall() { result = call }
|
||||
|
||||
override string toString() { result = "LocalCcCall(" + call + ")" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local call context given the call context and the callable that
|
||||
* the contexts apply to.
|
||||
*/
|
||||
LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) {
|
||||
ctx.relevantFor(callable) and
|
||||
if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable)
|
||||
then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall()
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -264,3 +264,5 @@ class DataFlowCall extends Expr {
|
||||
/** Gets the enclosing callable of this call. */
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -120,13 +120,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -152,7 +155,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -164,7 +167,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,14 +183,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,6 +225,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -462,13 +468,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -494,7 +503,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -506,7 +515,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -522,14 +531,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -562,6 +573,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -575,11 +587,22 @@ private module ImplCommon {
|
||||
exists(ArgumentNode arg | arg.argumentOf(call, -1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TCallContext =
|
||||
TAnyCallContext() or
|
||||
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
|
||||
reducedViableImplInCallContext(_, _, call) and
|
||||
recordDataFlowCallSite(call, _) and
|
||||
(emptyAp = true or emptyAp = false) and
|
||||
(
|
||||
exists(call.getArgument(i))
|
||||
@@ -593,6 +616,11 @@ private module ImplCommon {
|
||||
cached
|
||||
newtype TReturnPosition =
|
||||
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
|
||||
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -602,14 +630,15 @@ private module ImplCommon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context to restrict the targets of virtual dispatch and match the
|
||||
* call sites of flow into a method with flow out of a method.
|
||||
* A call context to restrict the targets of virtual dispatch, prune local flow,
|
||||
* and match the call sites of flow into a method with flow out of a method.
|
||||
*
|
||||
* There are four cases:
|
||||
* - `TAnyCallContext()` : No restrictions on method flow.
|
||||
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
|
||||
* parameter at the given `call`. This call improves the set of viable
|
||||
* dispatch targets for at least one method call in the current callable.
|
||||
* dispatch targets for at least one method call in the current callable
|
||||
* or helps prune unreachable nodes in the current callable.
|
||||
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
|
||||
* originating call does not improve the set of dispatch targets for any
|
||||
* method call in the current callable and was therefore not recorded.
|
||||
@@ -619,10 +648,15 @@ private module ImplCommon {
|
||||
*/
|
||||
abstract class CallContext extends TCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
@@ -633,16 +667,73 @@ private module ImplCommon {
|
||||
result = "CcCall(" + call + ", " + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
|
||||
}
|
||||
|
||||
class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context that is relevant for pruning local flow.
|
||||
*/
|
||||
abstract class LocalCallContext extends TLocalFlowCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class LocalCallContextAny extends LocalCallContext, TAnyLocalCall {
|
||||
override string toString() { result = "LocalCcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall {
|
||||
LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) }
|
||||
|
||||
DataFlowCall call;
|
||||
|
||||
DataFlowCall getCall() { result = call }
|
||||
|
||||
override string toString() { result = "LocalCcCall(" + call + ")" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local call context given the call context and the callable that
|
||||
* the contexts apply to.
|
||||
*/
|
||||
LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) {
|
||||
ctx.relevantFor(callable) and
|
||||
if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable)
|
||||
then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall()
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
|
||||
@@ -204,3 +204,5 @@ class DataFlowCall extends CallInstruction {
|
||||
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -120,13 +120,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -152,7 +155,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -164,7 +167,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,14 +183,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,6 +225,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -462,13 +468,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -494,7 +503,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -506,7 +515,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -522,14 +531,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -562,6 +573,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -575,11 +587,22 @@ private module ImplCommon {
|
||||
exists(ArgumentNode arg | arg.argumentOf(call, -1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TCallContext =
|
||||
TAnyCallContext() or
|
||||
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
|
||||
reducedViableImplInCallContext(_, _, call) and
|
||||
recordDataFlowCallSite(call, _) and
|
||||
(emptyAp = true or emptyAp = false) and
|
||||
(
|
||||
exists(call.getArgument(i))
|
||||
@@ -593,6 +616,11 @@ private module ImplCommon {
|
||||
cached
|
||||
newtype TReturnPosition =
|
||||
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
|
||||
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -602,14 +630,15 @@ private module ImplCommon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context to restrict the targets of virtual dispatch and match the
|
||||
* call sites of flow into a method with flow out of a method.
|
||||
* A call context to restrict the targets of virtual dispatch, prune local flow,
|
||||
* and match the call sites of flow into a method with flow out of a method.
|
||||
*
|
||||
* There are four cases:
|
||||
* - `TAnyCallContext()` : No restrictions on method flow.
|
||||
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
|
||||
* parameter at the given `call`. This call improves the set of viable
|
||||
* dispatch targets for at least one method call in the current callable.
|
||||
* dispatch targets for at least one method call in the current callable
|
||||
* or helps prune unreachable nodes in the current callable.
|
||||
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
|
||||
* originating call does not improve the set of dispatch targets for any
|
||||
* method call in the current callable and was therefore not recorded.
|
||||
@@ -619,10 +648,15 @@ private module ImplCommon {
|
||||
*/
|
||||
abstract class CallContext extends TCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
@@ -633,16 +667,73 @@ private module ImplCommon {
|
||||
result = "CcCall(" + call + ", " + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
|
||||
}
|
||||
|
||||
class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context that is relevant for pruning local flow.
|
||||
*/
|
||||
abstract class LocalCallContext extends TLocalFlowCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class LocalCallContextAny extends LocalCallContext, TAnyLocalCall {
|
||||
override string toString() { result = "LocalCcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall {
|
||||
LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) }
|
||||
|
||||
DataFlowCall call;
|
||||
|
||||
DataFlowCall getCall() { result = call }
|
||||
|
||||
override string toString() { result = "LocalCcCall(" + call + ")" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local call context given the call context and the callable that
|
||||
* the contexts apply to.
|
||||
*/
|
||||
LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) {
|
||||
ctx.relevantFor(callable) and
|
||||
if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable)
|
||||
then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall()
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
|
||||
@@ -1357,3 +1357,5 @@ class DataFlowExpr = DotNet::Expr;
|
||||
class DataFlowType = DotNet::Type;
|
||||
|
||||
class DataFlowLocation = Location;
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate localFlowStepPlus(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
|
||||
) {
|
||||
localFlowEntry(node1, config) and
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
localFlowEntry(node1, config) and
|
||||
(
|
||||
localFlowStep(node1, node2, config) and preservesValue = true
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
|
||||
) and
|
||||
node1 != node2 and
|
||||
nodeCand(node2, unbind(config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
|
||||
localFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, config, cc) and
|
||||
additionalLocalFlowStep(mid, node2, config) and
|
||||
not mid instanceof CastNode and
|
||||
preservesValue = false and
|
||||
nodeCand(node2, unbind(config))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
|
||||
* Holds if `node1` can step to `node2` in one or more local steps and this
|
||||
* path can occur as a maximal subsequence of local steps in a dataflow path.
|
||||
*/
|
||||
pragma[noinline]
|
||||
pragma[nomagic]
|
||||
private predicate localFlowBigStep(
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config
|
||||
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
|
||||
) {
|
||||
localFlowStepPlus(node1, node2, preservesValue, config) and
|
||||
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
|
||||
localFlowExit(node2, config)
|
||||
}
|
||||
|
||||
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
|
||||
(
|
||||
any(Configuration c).isSource(this)
|
||||
or
|
||||
localFlowBigStep(_, this, false, _)
|
||||
localFlowBigStep(_, this, false, _, _)
|
||||
or
|
||||
additionalJumpStep(_, this, _)
|
||||
)
|
||||
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
|
||||
(
|
||||
exists(Node mid |
|
||||
flowCandFwd(mid, fromArg, apf, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(mid, fromArg, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
apf = node.(AccessPathFrontNilNode).getApf()
|
||||
)
|
||||
or
|
||||
@@ -1122,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
|
||||
apf instanceof AccessPathFrontNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flowCand(mid, toReturn, apf, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathFrontNil nil |
|
||||
flowCandFwd(node, _, apf, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flowCand(mid, toReturn, nil, config) and
|
||||
apf instanceof AccessPathFrontNil
|
||||
)
|
||||
@@ -1363,12 +1368,12 @@ private predicate flowFwd0(
|
||||
(
|
||||
exists(Node mid |
|
||||
flowFwd(mid, fromArg, apf, ap, config) and
|
||||
localFlowBigStep(mid, node, true, config)
|
||||
localFlowBigStep(mid, node, true, config, _)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(mid, fromArg, _, nil, config) and
|
||||
localFlowBigStep(mid, node, false, config) and
|
||||
localFlowBigStep(mid, node, false, config, _) and
|
||||
ap = node.(AccessPathNilNode).getAp() and
|
||||
apf = ap.(AccessPathNil).getFront()
|
||||
)
|
||||
@@ -1472,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
|
||||
ap instanceof AccessPathNil
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowBigStep(node, mid, true, config) and
|
||||
localFlowBigStep(node, mid, true, config, _) and
|
||||
flow(mid, toReturn, ap, config)
|
||||
)
|
||||
or
|
||||
exists(Node mid, AccessPathNil nil |
|
||||
flowFwd(node, _, _, ap, config) and
|
||||
localFlowBigStep(node, mid, false, config) and
|
||||
localFlowBigStep(node, mid, false, config, _) and
|
||||
flow(mid, toReturn, nil, config) and
|
||||
ap instanceof AccessPathNil
|
||||
)
|
||||
@@ -1729,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
|
||||
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp()
|
||||
or
|
||||
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
|
||||
midnode = mid.getNode() and
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, conf, localCC) and
|
||||
ap = ap0
|
||||
or
|
||||
localFlowBigStep(midnode, node, false, conf, localCC) and
|
||||
ap0 instanceof AccessPathNil and
|
||||
ap = node.(AccessPathNilNode).getAp()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -1880,7 +1891,7 @@ private predicate pathIntoCallable(
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
@@ -2205,16 +2216,19 @@ private module FlowExploration {
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
additionalLocalFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getErasedRepr(node.getType())) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
jumpStep(mid.getNode(), node, config) and
|
||||
cc instanceof CallContextAny and
|
||||
@@ -2378,7 +2392,7 @@ private module FlowExploration {
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, emptyAp)
|
||||
else innercc = TSomeCall(p, emptyAp)
|
||||
)
|
||||
|
||||
@@ -120,13 +120,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -152,7 +155,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -164,7 +167,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,14 +183,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,6 +225,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -462,13 +468,16 @@ private module ImplCommon {
|
||||
int i, ArgumentNode arg, CallContext outercc, DataFlowCall call
|
||||
) {
|
||||
exists(DataFlowCallable c | argumentOf(call, i, arg, c) |
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
reducedViableImplInCallContext(_, c, other)
|
||||
)
|
||||
(
|
||||
outercc = TAnyCallContext()
|
||||
or
|
||||
outercc = TSomeCall(getAParameter(c), _)
|
||||
or
|
||||
exists(DataFlowCall other | outercc = TSpecificCall(other, _, _) |
|
||||
recordDataFlowCallSite(other, c)
|
||||
)
|
||||
) and
|
||||
not isUnreachableInCall(arg, outercc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -494,7 +503,7 @@ private module ImplCommon {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
viableParamArg1(p, callable, i, arg, outercc, call)
|
||||
|
|
||||
if reducedViableImplInCallContext(_, callable, call)
|
||||
if recordDataFlowCallSite(call, callable)
|
||||
then innercc = TSpecificCall(call, i, true)
|
||||
else innercc = TSomeCall(p, true)
|
||||
)
|
||||
@@ -506,7 +515,7 @@ private module ImplCommon {
|
||||
exists(DataFlowCall call, int i, DataFlowCallable callable |
|
||||
result = TSpecificCall(call, i, _) and
|
||||
p.isParameterOf(callable, i) and
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
recordDataFlowCallSite(call, callable)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -522,14 +531,16 @@ private module ImplCommon {
|
||||
exists(Node mid |
|
||||
parameterValueFlow(p, mid, cc) and
|
||||
step(mid, node) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
or
|
||||
// flow through a callable
|
||||
exists(Node arg |
|
||||
parameterValueFlow(p, arg, cc) and
|
||||
argumentValueFlowsThrough(arg, node, cc) and
|
||||
compatibleTypes(p.getType(), node.getType())
|
||||
compatibleTypes(p.getType(), node.getType()) and
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -562,6 +573,7 @@ private module ImplCommon {
|
||||
argumentValueFlowsThrough0(call, arg, kind, cc)
|
||||
|
|
||||
out = getAnOutNode(call, kind) and
|
||||
not isUnreachableInCall(out, cc.(CallContextSpecificCall).getCall()) and
|
||||
compatibleTypes(arg.getType(), out.getType())
|
||||
)
|
||||
}
|
||||
@@ -575,11 +587,22 @@ private module ImplCommon {
|
||||
exists(ArgumentNode arg | arg.argumentOf(call, -1))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
*/
|
||||
cached
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
newtype TCallContext =
|
||||
TAnyCallContext() or
|
||||
TSpecificCall(DataFlowCall call, int i, boolean emptyAp) {
|
||||
reducedViableImplInCallContext(_, _, call) and
|
||||
recordDataFlowCallSite(call, _) and
|
||||
(emptyAp = true or emptyAp = false) and
|
||||
(
|
||||
exists(call.getArgument(i))
|
||||
@@ -593,6 +616,11 @@ private module ImplCommon {
|
||||
cached
|
||||
newtype TReturnPosition =
|
||||
TReturnPosition0(DataFlowCallable c, ReturnKind kind) { returnPosition(_, c, kind) }
|
||||
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -602,14 +630,15 @@ private module ImplCommon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context to restrict the targets of virtual dispatch and match the
|
||||
* call sites of flow into a method with flow out of a method.
|
||||
* A call context to restrict the targets of virtual dispatch, prune local flow,
|
||||
* and match the call sites of flow into a method with flow out of a method.
|
||||
*
|
||||
* There are four cases:
|
||||
* - `TAnyCallContext()` : No restrictions on method flow.
|
||||
* - `TSpecificCall(DataFlowCall call, int i)` : Flow entered through the `i`th
|
||||
* parameter at the given `call`. This call improves the set of viable
|
||||
* dispatch targets for at least one method call in the current callable.
|
||||
* dispatch targets for at least one method call in the current callable
|
||||
* or helps prune unreachable nodes in the current callable.
|
||||
* - `TSomeCall(ParameterNode p)` : Flow entered through parameter `p`. The
|
||||
* originating call does not improve the set of dispatch targets for any
|
||||
* method call in the current callable and was therefore not recorded.
|
||||
@@ -619,10 +648,15 @@ private module ImplCommon {
|
||||
*/
|
||||
abstract class CallContext extends TCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class CallContextAny extends CallContext, TAnyCallContext {
|
||||
override string toString() { result = "CcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
abstract class CallContextCall extends CallContext { }
|
||||
@@ -633,16 +667,73 @@ private module ImplCommon {
|
||||
result = "CcCall(" + call + ", " + i + ")"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
recordDataFlowCallSite(getCall(), callable)
|
||||
}
|
||||
|
||||
DataFlowCall getCall() { this = TSpecificCall(result, _, _) }
|
||||
}
|
||||
|
||||
class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | this = TSomeCall(p, _) and p.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
class CallContextReturn extends CallContext, TReturn {
|
||||
override string toString() {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")")
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call context that is relevant for pruning local flow.
|
||||
*/
|
||||
abstract class LocalCallContext extends TLocalFlowCallContext {
|
||||
abstract string toString();
|
||||
|
||||
/** Holds if this call context is relevant for `callable`. */
|
||||
abstract predicate relevantFor(DataFlowCallable callable);
|
||||
}
|
||||
|
||||
class LocalCallContextAny extends LocalCallContext, TAnyLocalCall {
|
||||
override string toString() { result = "LocalCcAny" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { any() }
|
||||
}
|
||||
|
||||
class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall {
|
||||
LocalCallContextSpecificCall() { this = TSpecificLocalCall(call) }
|
||||
|
||||
DataFlowCall call;
|
||||
|
||||
DataFlowCall getCall() { result = call }
|
||||
|
||||
override string toString() { result = "LocalCcCall(" + call + ")" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) { relevantLocalCCtx(call, callable) }
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local call context given the call context and the callable that
|
||||
* the contexts apply to.
|
||||
*/
|
||||
LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable) {
|
||||
ctx.relevantFor(callable) and
|
||||
if relevantLocalCCtx(ctx.(CallContextSpecificCall).getCall(), callable)
|
||||
then result.(LocalCallContextSpecificCall).getCall() = ctx.(CallContextSpecificCall).getCall()
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
private import java
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon::Public
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.java.controlflow.Guards
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
|
||||
@@ -283,3 +285,42 @@ class DataFlowCall extends Call {
|
||||
/** Gets the data flow node corresponding to this call. */
|
||||
ExprNode getNode() { result.getExpr() = this }
|
||||
}
|
||||
|
||||
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
|
||||
private predicate constantBooleanExpr(Expr e, boolean val) {
|
||||
e.(CompileTimeConstantExpr).getBooleanValue() = val
|
||||
or
|
||||
exists(SsaExplicitUpdate v, Expr src |
|
||||
e = v.getAUse() and
|
||||
src = v.getDefiningExpr().(VariableAssign).getSource() and
|
||||
constantBooleanExpr(src, val)
|
||||
)
|
||||
}
|
||||
|
||||
/** An argument that always has the same Boolean value. */
|
||||
private class ConstantBooleanArgumentNode extends ArgumentNode, ExprNode {
|
||||
ConstantBooleanArgumentNode() { constantBooleanExpr(this.getExpr(), _) }
|
||||
|
||||
/** Gets the Boolean value of this expression. */
|
||||
boolean getBooleanValue() { constantBooleanExpr(this.getExpr(), result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
*/
|
||||
cached
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
exists(
|
||||
ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param,
|
||||
Guard guard
|
||||
|
|
||||
// get constant bool argument and parameter for this call
|
||||
viableParamArg(call, paramNode, arg) and
|
||||
// get the ssa variable definition for this parameter
|
||||
param.isParameterDefinition(paramNode.getParameter()) and
|
||||
// which is used in a guard
|
||||
param.getAUse() = guard and
|
||||
// which controls `n` with the opposite value of `arg`
|
||||
guard.controls(n.asExpr().getBasicBlock(), arg.getBooleanValue().booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
132
java/ql/test/library-tests/dataflow/call-sensitivity/A.java
Normal file
132
java/ql/test/library-tests/dataflow/call-sensitivity/A.java
Normal file
@@ -0,0 +1,132 @@
|
||||
public class A {
|
||||
|
||||
public static void sink(Object o) {
|
||||
}
|
||||
|
||||
public Object flowThrough(Object o, boolean cond) {
|
||||
if (cond) {
|
||||
return o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void callSinkIfTrue(Object o, boolean cond) {
|
||||
if (cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void callSinkIfFalse(Object o, boolean cond) {
|
||||
if (!cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void callSinkFromLoop(Object o, boolean cond) {
|
||||
while (cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void localCallSensitivity(Object o, boolean c) {
|
||||
Object o1 = o;
|
||||
Object o2 = null;
|
||||
if (c) {
|
||||
Object tmp = o1;
|
||||
o2 = 1 == 1 ? (tmp) : (tmp);
|
||||
}
|
||||
Object o3 = o2;
|
||||
sink(o3);
|
||||
}
|
||||
|
||||
public void localCallSensitivity2(Object o, boolean b, boolean c) {
|
||||
Object o1 = o;
|
||||
Object o2 = null;
|
||||
if (b || c) {
|
||||
Object tmp = o1;
|
||||
o2 = 1 == 1 ? (tmp) : (tmp);
|
||||
}
|
||||
Object o3 = o2;
|
||||
sink(o3);
|
||||
}
|
||||
|
||||
public void f1() {
|
||||
// should not exhibit flow
|
||||
callSinkIfTrue(new Integer(1), false);
|
||||
callSinkIfFalse(new Integer(2), true);
|
||||
callSinkFromLoop(new Integer(3), false);
|
||||
localCallSensitivity(new Integer(4), false);
|
||||
sink(flowThrough(new Integer(4), false));
|
||||
// should exhibit flow
|
||||
callSinkIfTrue(new Integer(1), true);
|
||||
callSinkIfFalse(new Integer(2), false);
|
||||
callSinkFromLoop(new Integer(3), true);
|
||||
localCallSensitivity(new Integer(4), true);
|
||||
localCallSensitivity2(new Integer(4), true, true);
|
||||
localCallSensitivity2(new Integer(4), false, true);
|
||||
localCallSensitivity2(new Integer(4), true, false);
|
||||
sink(flowThrough(new Integer(4), true));
|
||||
// expected false positive
|
||||
localCallSensitivity2(new Integer(4), false, false);
|
||||
}
|
||||
|
||||
public void f2() {
|
||||
boolean t = true;
|
||||
boolean f = false;
|
||||
// should not exhibit flow
|
||||
callSinkIfTrue(new Integer(4), f);
|
||||
callSinkIfFalse(new Integer(5), t);
|
||||
callSinkFromLoop(new Integer(6), f);
|
||||
localCallSensitivity(new Integer(4), f);
|
||||
sink(flowThrough(new Integer(4), f));
|
||||
// should exhibit flow
|
||||
callSinkIfTrue(new Integer(4), t);
|
||||
callSinkIfFalse(new Integer(5), f);
|
||||
callSinkFromLoop(new Integer(6), t);
|
||||
localCallSensitivity(new Integer(4), t);
|
||||
sink(flowThrough(new Integer(4), t));
|
||||
}
|
||||
|
||||
public void f3(InterfaceA b) {
|
||||
boolean t = true;
|
||||
boolean f = false;
|
||||
// should not exhibit flow
|
||||
b.callSinkIfTrue(new Integer(4), f);
|
||||
b.callSinkIfFalse(new Integer(5), t);
|
||||
b.localCallSensitivity(new Integer(4), f);
|
||||
// should exhibit flow
|
||||
b.callSinkIfTrue(new Integer(4), t);
|
||||
b.callSinkIfFalse(new Integer(5), f);
|
||||
b.localCallSensitivity(new Integer(4), t);
|
||||
}
|
||||
|
||||
class B implements InterfaceA {
|
||||
@Override
|
||||
public void callSinkIfTrue(Object o, boolean cond) {
|
||||
if (cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callSinkIfFalse(Object o, boolean cond) {
|
||||
if (!cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void localCallSensitivity(Object o, boolean c) {
|
||||
Object o1 = o;
|
||||
Object o2 = null;
|
||||
if (c) {
|
||||
Object tmp = o1;
|
||||
o2 = 1 == 1 ? (tmp) : (tmp);
|
||||
}
|
||||
Object o3 = o2;
|
||||
sink(o3);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
42
java/ql/test/library-tests/dataflow/call-sensitivity/A2.java
Normal file
42
java/ql/test/library-tests/dataflow/call-sensitivity/A2.java
Normal file
@@ -0,0 +1,42 @@
|
||||
public class A2 {
|
||||
|
||||
public static void sink(Object o) {
|
||||
}
|
||||
|
||||
public void m() {
|
||||
|
||||
}
|
||||
|
||||
public void callsite(InterfaceB intF) {
|
||||
B b = new B();
|
||||
// in both possible implementations of foo, this callsite is relevant
|
||||
// in IntA, it improves virtual dispatch,
|
||||
// and in IntB, it improves the dataflow analysis.
|
||||
intF.foo(b, new Integer(5), false);
|
||||
}
|
||||
|
||||
private class B extends A2 {
|
||||
@Override
|
||||
public void m() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class IntA implements InterfaceB {
|
||||
@Override
|
||||
public void foo(A2 obj, Object o, boolean cond) {
|
||||
obj.m();
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
|
||||
private class IntB implements InterfaceB {
|
||||
@Override
|
||||
public void foo(A2 obj, Object o, boolean cond) {
|
||||
if (cond) {
|
||||
sink(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
public interface InterfaceA {
|
||||
public void callSinkIfTrue(Object o, boolean cond);
|
||||
public void callSinkIfFalse(Object o, boolean cond);
|
||||
public void localCallSensitivity(Object o, boolean c);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
public interface InterfaceB {
|
||||
public void foo(A2 a, Object o, boolean cond);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
edges
|
||||
| A2.java:15:15:15:28 | new Integer(...) : Number | A2.java:27:27:27:34 | o : Number |
|
||||
| A2.java:27:27:27:34 | o : Number | A2.java:29:9:29:9 | o |
|
||||
| A.java:14:29:14:36 | o : Number | A.java:16:9:16:9 | o |
|
||||
| A.java:20:30:20:37 | o : Number | A.java:22:9:22:9 | o |
|
||||
| A.java:26:31:26:38 | o : Number | A.java:28:9:28:9 | o |
|
||||
| A.java:32:35:32:42 | o : Number | A.java:40:8:40:9 | o3 |
|
||||
| A.java:43:36:43:43 | o : Number | A.java:51:8:51:9 | o3 |
|
||||
| A.java:43:36:43:43 | o : Number | A.java:51:8:51:9 | o3 |
|
||||
| A.java:43:36:43:43 | o : Number | A.java:51:8:51:9 | o3 |
|
||||
| A.java:62:18:62:31 | new Integer(...) : Number | A.java:14:29:14:36 | o : Number |
|
||||
| A.java:63:19:63:32 | new Integer(...) : Number | A.java:20:30:20:37 | o : Number |
|
||||
| A.java:64:20:64:33 | new Integer(...) : Number | A.java:26:31:26:38 | o : Number |
|
||||
| A.java:65:24:65:37 | new Integer(...) : Number | A.java:32:35:32:42 | o : Number |
|
||||
| A.java:66:25:66:38 | new Integer(...) : Number | A.java:43:36:43:43 | o : Number |
|
||||
| A.java:67:25:67:38 | new Integer(...) : Number | A.java:43:36:43:43 | o : Number |
|
||||
| A.java:68:25:68:38 | new Integer(...) : Number | A.java:43:36:43:43 | o : Number |
|
||||
| A.java:69:20:69:33 | new Integer(...) : Number | A.java:69:8:69:40 | flowThrough(...) |
|
||||
| A.java:71:25:71:38 | new Integer(...) : Number | A.java:43:36:43:43 | o : Number |
|
||||
| A.java:84:18:84:31 | new Integer(...) : Number | A.java:14:29:14:36 | o : Number |
|
||||
| A.java:85:19:85:32 | new Integer(...) : Number | A.java:20:30:20:37 | o : Number |
|
||||
| A.java:86:20:86:33 | new Integer(...) : Number | A.java:26:31:26:38 | o : Number |
|
||||
| A.java:87:24:87:37 | new Integer(...) : Number | A.java:32:35:32:42 | o : Number |
|
||||
| A.java:88:20:88:33 | new Integer(...) : Number | A.java:88:8:88:37 | flowThrough(...) |
|
||||
| A.java:99:20:99:33 | new Integer(...) : Number | A.java:106:30:106:37 | o : Number |
|
||||
| A.java:100:21:100:34 | new Integer(...) : Number | A.java:113:31:113:38 | o : Number |
|
||||
| A.java:101:26:101:39 | new Integer(...) : Number | A.java:120:36:120:43 | o : Number |
|
||||
| A.java:106:30:106:37 | o : Number | A.java:108:10:108:10 | o |
|
||||
| A.java:113:31:113:38 | o : Number | A.java:115:10:115:10 | o |
|
||||
| A.java:120:36:120:43 | o : Number | A.java:128:9:128:10 | o3 |
|
||||
nodes
|
||||
| A2.java:15:15:15:28 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A2.java:27:27:27:34 | o : Number | semmle.label | o : Number |
|
||||
| A2.java:29:9:29:9 | o | semmle.label | o |
|
||||
| A2.java:37:10:37:10 | o | semmle.label | o |
|
||||
| A.java:14:29:14:36 | o : Number | semmle.label | o : Number |
|
||||
| A.java:16:9:16:9 | o | semmle.label | o |
|
||||
| A.java:20:30:20:37 | o : Number | semmle.label | o : Number |
|
||||
| A.java:22:9:22:9 | o | semmle.label | o |
|
||||
| A.java:26:31:26:38 | o : Number | semmle.label | o : Number |
|
||||
| A.java:28:9:28:9 | o | semmle.label | o |
|
||||
| A.java:32:35:32:42 | o : Number | semmle.label | o : Number |
|
||||
| A.java:40:8:40:9 | o3 | semmle.label | o3 |
|
||||
| A.java:43:36:43:43 | o : Number | semmle.label | o : Number |
|
||||
| A.java:43:36:43:43 | o : Number | semmle.label | o : Number |
|
||||
| A.java:43:36:43:43 | o : Number | semmle.label | o : Number |
|
||||
| A.java:51:8:51:9 | o3 | semmle.label | o3 |
|
||||
| A.java:62:18:62:31 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:63:19:63:32 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:64:20:64:33 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:65:24:65:37 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:66:25:66:38 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:67:25:67:38 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:68:25:68:38 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:69:8:69:40 | flowThrough(...) | semmle.label | flowThrough(...) |
|
||||
| A.java:69:20:69:33 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:71:25:71:38 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:84:18:84:31 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:85:19:85:32 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:86:20:86:33 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:87:24:87:37 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:88:8:88:37 | flowThrough(...) | semmle.label | flowThrough(...) |
|
||||
| A.java:88:20:88:33 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:99:20:99:33 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:100:21:100:34 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:101:26:101:39 | new Integer(...) : Number | semmle.label | new Integer(...) : Number |
|
||||
| A.java:106:30:106:37 | o : Number | semmle.label | o : Number |
|
||||
| A.java:108:10:108:10 | o | semmle.label | o |
|
||||
| A.java:113:31:113:38 | o : Number | semmle.label | o : Number |
|
||||
| A.java:115:10:115:10 | o | semmle.label | o |
|
||||
| A.java:120:36:120:43 | o : Number | semmle.label | o : Number |
|
||||
| A.java:128:9:128:10 | o3 | semmle.label | o3 |
|
||||
#select
|
||||
| A2.java:15:15:15:28 | new Integer(...) : Number | A2.java:15:15:15:28 | new Integer(...) : Number | A2.java:29:9:29:9 | o | $@ | A2.java:29:9:29:9 | o | o |
|
||||
| A.java:62:18:62:31 | new Integer(...) : Number | A.java:62:18:62:31 | new Integer(...) : Number | A.java:16:9:16:9 | o | $@ | A.java:16:9:16:9 | o | o |
|
||||
| A.java:63:19:63:32 | new Integer(...) : Number | A.java:63:19:63:32 | new Integer(...) : Number | A.java:22:9:22:9 | o | $@ | A.java:22:9:22:9 | o | o |
|
||||
| A.java:64:20:64:33 | new Integer(...) : Number | A.java:64:20:64:33 | new Integer(...) : Number | A.java:28:9:28:9 | o | $@ | A.java:28:9:28:9 | o | o |
|
||||
| A.java:65:24:65:37 | new Integer(...) : Number | A.java:65:24:65:37 | new Integer(...) : Number | A.java:40:8:40:9 | o3 | $@ | A.java:40:8:40:9 | o3 | o3 |
|
||||
| A.java:66:25:66:38 | new Integer(...) : Number | A.java:66:25:66:38 | new Integer(...) : Number | A.java:51:8:51:9 | o3 | $@ | A.java:51:8:51:9 | o3 | o3 |
|
||||
| A.java:67:25:67:38 | new Integer(...) : Number | A.java:67:25:67:38 | new Integer(...) : Number | A.java:51:8:51:9 | o3 | $@ | A.java:51:8:51:9 | o3 | o3 |
|
||||
| A.java:68:25:68:38 | new Integer(...) : Number | A.java:68:25:68:38 | new Integer(...) : Number | A.java:51:8:51:9 | o3 | $@ | A.java:51:8:51:9 | o3 | o3 |
|
||||
| A.java:69:20:69:33 | new Integer(...) : Number | A.java:69:20:69:33 | new Integer(...) : Number | A.java:69:8:69:40 | flowThrough(...) | $@ | A.java:69:8:69:40 | flowThrough(...) | flowThrough(...) |
|
||||
| A.java:71:25:71:38 | new Integer(...) : Number | A.java:71:25:71:38 | new Integer(...) : Number | A.java:51:8:51:9 | o3 | $@ | A.java:51:8:51:9 | o3 | o3 |
|
||||
| A.java:84:18:84:31 | new Integer(...) : Number | A.java:84:18:84:31 | new Integer(...) : Number | A.java:16:9:16:9 | o | $@ | A.java:16:9:16:9 | o | o |
|
||||
| A.java:85:19:85:32 | new Integer(...) : Number | A.java:85:19:85:32 | new Integer(...) : Number | A.java:22:9:22:9 | o | $@ | A.java:22:9:22:9 | o | o |
|
||||
| A.java:86:20:86:33 | new Integer(...) : Number | A.java:86:20:86:33 | new Integer(...) : Number | A.java:28:9:28:9 | o | $@ | A.java:28:9:28:9 | o | o |
|
||||
| A.java:87:24:87:37 | new Integer(...) : Number | A.java:87:24:87:37 | new Integer(...) : Number | A.java:40:8:40:9 | o3 | $@ | A.java:40:8:40:9 | o3 | o3 |
|
||||
| A.java:88:20:88:33 | new Integer(...) : Number | A.java:88:20:88:33 | new Integer(...) : Number | A.java:88:8:88:37 | flowThrough(...) | $@ | A.java:88:8:88:37 | flowThrough(...) | flowThrough(...) |
|
||||
| A.java:99:20:99:33 | new Integer(...) : Number | A.java:99:20:99:33 | new Integer(...) : Number | A.java:108:10:108:10 | o | $@ | A.java:108:10:108:10 | o | o |
|
||||
| A.java:100:21:100:34 | new Integer(...) : Number | A.java:100:21:100:34 | new Integer(...) : Number | A.java:115:10:115:10 | o | $@ | A.java:115:10:115:10 | o | o |
|
||||
| A.java:101:26:101:39 | new Integer(...) : Number | A.java:101:26:101:39 | new Integer(...) : Number | A.java:128:9:128:10 | o3 | $@ | A.java:128:9:128:10 | o3 | o3 |
|
||||
24
java/ql/test/library-tests/dataflow/call-sensitivity/flow.ql
Normal file
24
java/ql/test/library-tests/dataflow/call-sensitivity/flow.ql
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class Conf extends DataFlow::Configuration {
|
||||
Conf() { this = "CallSensitiveFlowConf" }
|
||||
|
||||
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassInstanceExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().hasName("sink") and
|
||||
ma.getAnArgument() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select source, source, sink, "$@", sink, sink.toString()
|
||||
Reference in New Issue
Block a user