Sync data-flow libraries

As of 2021-05-12
This commit is contained in:
Owen Mansel-Chan
2021-05-12 08:54:11 +01:00
parent 879666682d
commit a86390d850
3 changed files with 340 additions and 279 deletions

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and
jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg |
exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
) {
exists(ParameterNode p |
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
this instanceof CastNode or
clearsContent(this, _)
castNode(this) or
clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getNodeType(node1)
t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getNodeType(node2)
t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p;
private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node))
ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
nodeIsHidden(this.getNode()) and
hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node))
ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgumentNode arg |
exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p)
TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and
not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType())
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node))
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`.
*/
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
(
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
simpleLocalFlowStepExt(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and
jumpStepCached(node1, node2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg |
exists(ArgNode arg |
fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg)
)
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic]
predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
viableParamArg(call, p, arg) and
fwdFlow(arg, config)
}
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
) {
exists(ParameterNode p |
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
exists(ParamNode p |
revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config)
)
}
pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config)
}
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic]
private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/
pragma[nomagic]
private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
)
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic]
private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/
private class FlowCheckNode extends Node {
FlowCheckNode() {
this instanceof CastNode or
clearsContent(this, _)
castNode(this) or
clearsContentCached(this, _)
}
}
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
node instanceof ParameterNode or
node instanceof ParamNode or
node instanceof OutNodeExt or
store(_, _, node, _) or
read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc
) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getNodeType(node1)
t = getNodeDataFlowType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getNodeType(node2)
t = getNodeDataFlowType(node2)
) and
node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
or
exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getNodeType(node2) and
t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config))
)
)
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap]
private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
}
bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
}
bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic]
private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
Configuration config
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config
) {
exists(ArgumentNode arg, boolean allowsFieldFlow |
exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
)
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
Configuration config
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
exists(ParameterNode p, boolean allowsFieldFlow |
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
}
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline]
private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) {
revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p)
}
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
}
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p;
private ParamNode p;
private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node))
ap = TAccessPathNil(getNodeDataFlowType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() }
private predicate isHidden() {
nodeIsHidden(this.getNode()) and
hiddenNode(this.getNode()) and
not this.isSource() and
not this instanceof PathNodeSink
}
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node))
ap = TAccessPathNil(getNodeDataFlowType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) {
exists(ArgumentNode arg |
exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
exists(ParameterNode p |
exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i)
)
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively.
*/
private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call
) {
exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 =
TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p)
TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 =
TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and
not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
)
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and
not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType())
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
)
}
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config
) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
)
or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and
ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node))
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
exists(ArgumentNode arg |
exists(ArgNode arg |
arg = mid.getNode() and
cc = mid.getCallContext() and
arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
}
private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config
) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config
) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
)
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config)
)
or
exists(ParameterNode p |
exists(ParamNode p |
mid.getNode() = p and
viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config
) {
exists(PartialPathNodeRev mid, ParameterNode p |
exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and
p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic]
private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) {
exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/
private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i)
}
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i)
}
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i)
)
}
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParamLambda(call, i, p) and
arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node))
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeDataFlowType(node))
else any()
}
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall
) {
lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and
t = getNodeDataFlowType(node) and
toReturn = false and
toJump = false and
lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and
lastCall = TDataFlowCallNone()
|
jumpStep(node, mid) and
jumpStepCached(node, mid) and
t = t0
or
exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
preservesValue = false and
t = getNodeType(node)
t = getNodeDataFlowType(node)
or
preservesValue = true and
t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
)
or
// flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
(
if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic]
predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall
) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached
private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/**
* Gets a viable target for the lambda call `call`.
*
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`.
*/
pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i)
}
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account.
*/
cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p))
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
)
}
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`.
*/
pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and
read = false
or
@@ -325,30 +408,30 @@ private module Cached {
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and
read(mid, _, node) and
read = true
)
or
// flow through: no prior read
exists(ArgumentNode arg |
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read)
)
or
// flow through: no read inside method
exists(ArgumentNode arg |
exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false)
)
}
pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read)
}
pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
}
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return
* node.
*/
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and
kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic]
private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) {
exists(ParameterNode param | viableParamArg(call, param, arg) |
exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read)
)
}
@@ -382,14 +465,14 @@ private module Cached {
*
* `read` indicates whether it is contents of `arg` that can flow to `out`.
*/
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
)
}
predicate cand(ParameterNode p, Node n) {
predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and
(
parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type.
*/
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and
if node instanceof CastingNode
then
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node))
compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or
// getter
compatibleTypes(read.getContentType(), getNodeType(node))
compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any()
}
pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and
Cand::cand(p, _) and
read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType())
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
)
or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic]
private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) {
// flow through: no prior read
exists(ArgumentNode arg |
exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node)
)
or
// flow through: no read inside method
exists(ArgumentNode arg |
exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node)
)
}
pragma[nomagic]
private predicate parameterValueFlowArg(
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _)
}
pragma[nomagic]
private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) {
exists(ParameterNode param | viableParamArg(call, param, arg) |
exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read)
)
}
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type.
*/
pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind)
|
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out))
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or
// getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out))
compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
)
}
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*/
predicate getterStep(ArgumentNode arg, Content c, Node out) {
predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type.
*/
private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
ParamNode p, ReturnKind kind, ReadStepTypesOption read
) {
exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable)
or
callable = call.getEnclosingCallable() and
callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
}
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts
)
}
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps.
*/
cached
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
readStep(_, c, _) and
contentType = getNodeType(node1) and
containerType = getNodeType(node2)
read(_, c, _) and
contentType = getNodeDataFlowType(node1) and
containerType = getNodeDataFlowType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readStep(n2, c, n1) and
contentType = getNodeType(n1) and
containerType = getNodeType(n2)
read(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent
* interface.
*/
cached
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
private predicate reverseStepThroughInputOutputAlias(
PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow
// from function input to output?
fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgNode), fromPre)
)
or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
)
}
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call)
or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
}
cached
@@ -726,12 +816,12 @@ private module Cached {
cached
newtype TLocalFlowCallContext =
TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached
newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached
newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked.
*/
class CastingNode extends Node {
CastingNode() {
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
CastingNode() { castingNode(this) }
}
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
readStep(n1, c, n2) and
container = getNodeType(n1) and
content = getNodeType(n2)
read(n1, c, n2) and
container = getNodeDataFlowType(n1) and
content = getNodeDataFlowType(n2)
}
private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
}
override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
}
override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
}
}
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
}
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
}
/**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
class ArgNode extends Node {
ArgNode() { argumentNode(this, _, _) }
/** Holds if this argument occurs at the given position in the given call. */
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
}
/**
* A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/
class ReturnNodeExt extends Node {
ReturnNodeExt() {
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
ReturnNodeExt() { returnNodeExt(this, _) }
/** Gets the kind of this returned value. */
ReturnKindExt getKind() {
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
ReturnKindExt getKind() { returnNodeExt(this, result) }
}
/**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument.
*/
class OutNodeExt extends Node {
OutNodeExt() {
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
OutNodeExt() { outNodeExt(this) }
}
/**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call);
final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
}
class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
}
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos }
override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
}
/** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/
pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 |
pragma[only_bind_into](n0) = n and
pragma[only_bind_into](result) = n0.getEnclosingCallable()
)
nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
}
/** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
}
pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call)
or
exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and
callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call)
)
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn
}
predicate read = readStep/3;
/** An optional Boolean value. */
class BooleanOption extends TBooleanOption {
string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {