Merge pull request #2099 from aschackmull/java/callcontext-bool-pruning

Java: Data-flow pruning based on call contexts.
This commit is contained in:
Tom Hvitved
2019-10-15 09:36:36 +02:00
committed by GitHub
33 changed files with 2085 additions and 1111 deletions

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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. */

View File

@@ -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)
)

View File

@@ -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

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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. */

View File

@@ -204,3 +204,5 @@ class DataFlowCall extends CallInstruction {
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
}
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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. */

View File

@@ -1357,3 +1357,5 @@ class DataFlowExpr = DotNet::Expr;
class DataFlowType = DotNet::Type;
class DataFlowLocation = Location;
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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. */

View File

@@ -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())
)
}

View 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);
}
}
}

View 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);
}
}
}
}

View File

@@ -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);
}

View File

@@ -0,0 +1,3 @@
public interface InterfaceB {
public void foo(A2 a, Object o, boolean cond);
}

View File

@@ -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 |

View 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()