mirror of
https://github.com/github/codeql.git
synced 2026-01-29 14:23:03 +01:00
Sync shared dataflow libraries
This commit is contained in:
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2132,7 +2134,7 @@ private module Stage4 {
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2149,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2159,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2175,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2193,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2217,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2271,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2306,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2325,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2350,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2398,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2412,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2467,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2536,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2558,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2591,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2763,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2777,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3074,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3086,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3129,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3317,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3329,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3415,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3430,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3452,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3596,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3613,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3672,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3680,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2132,7 +2134,7 @@ private module Stage4 {
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2149,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2159,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2175,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2193,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2217,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2271,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2306,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2325,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2350,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2398,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2412,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2467,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2536,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2558,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2591,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2763,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2777,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3074,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3086,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3129,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3317,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3329,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3415,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3430,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3452,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3596,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3613,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3672,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3680,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
*
|
||||
* The analysis uses non-linear recursion: When computing a flow path in or out
|
||||
* of a call, we use the results of the analysis recursively to resolve lambda
|
||||
* 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) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TReturnPositionSimple =
|
||||
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
|
||||
exists(ReturnNode ret |
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallable(call), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosNonLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
|
||||
* the lambda call `lambdaCall`.
|
||||
*
|
||||
* The parameter `toReturn` indicates whether the path from `node` to
|
||||
* `lambdaCall` goes through a return, and `toJump` whether the path goes
|
||||
* through a jump step.
|
||||
*
|
||||
* The call context `lastCall` records the last call on the path from `node`
|
||||
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
|
||||
* callable of `lambdaCall`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
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))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
then lastCall = TDataFlowCallSome(call)
|
||||
else lastCall = lastCall0
|
||||
) and
|
||||
toReturn = false
|
||||
|
|
||||
viableParamArgNonLambda(call, p, node)
|
||||
or
|
||||
viableParamArgLambda(call, p, node) // non-linear recursion
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOutLambdaCall(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
|
||||
DataFlowCall call, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
exists(ReturnKindExt rk |
|
||||
out = rk.getAnOutNode(call) and
|
||||
lambdaCall(call, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
exists(DataFlowCall call, OutNode out |
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
viableReturnPosOutNonLambda(call, pos, out)
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
result = viableCallable(call)
|
||||
or
|
||||
result = viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
* `lastCall` records the call required to reach `call` in order for the result
|
||||
* to be a viable target, if any.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
|
||||
exists(Node creation, LambdaCallKind kind |
|
||||
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
|
||||
lambdaCreation(creation, kind, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +280,7 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
viableCallable(call) = result.getCallable() and
|
||||
viableCallableExt(call) = result.getCallable() and
|
||||
kind = result.getKind()
|
||||
}
|
||||
|
||||
@@ -317,6 +545,35 @@ private module Cached {
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx)
|
||||
or
|
||||
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
|
||||
or
|
||||
exists(DataFlowCallable enclosing |
|
||||
mayBenefitFromCallContextExt(call, enclosing) and
|
||||
enclosing = viableCallableExt(ctx) and
|
||||
result = viableCallableLambda(call, TDataFlowCallNone())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
@@ -324,10 +581,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
mayBenefitFromCallContextExt(call, c) and
|
||||
c = viableCallableExt(ctx) and
|
||||
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(viableCallableExt(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -339,7 +596,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
@@ -351,10 +608,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
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
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -367,7 +624,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
@@ -415,6 +672,30 @@ private module Cached {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
|
||||
* nodes of some function output and input respectively, where the output and input
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
|
|
||||
exists(DataFlowCall c |
|
||||
// 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)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -423,7 +704,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -457,6 +738,11 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallOption =
|
||||
TDataFlowCallNone() or
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
@@ -568,7 +854,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -613,7 +899,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,9 +1008,22 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
string toString() { result = "[" + kind + "] " + c }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
|
||||
* predicate ensures that joins go from `n` to the result instead of the other
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
|
||||
result = ret.getEnclosingCallable()
|
||||
result = getNodeEnclosingCallable(ret)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -740,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
|
||||
bindingset[cc, callable]
|
||||
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
|
||||
cc instanceof CallContextAny and callable = viableCallable(call)
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
@@ -754,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
|
||||
if reducedViableImplInCallContext(call, _, ctx)
|
||||
then result = prunedViableImplInCallContext(call, ctx)
|
||||
else result = viableCallable(call)
|
||||
else result = viableCallableExt(call)
|
||||
)
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextSomeCall
|
||||
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextAny
|
||||
result = viableCallableExt(call) and cc instanceof CallContextAny
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
@@ -775,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `DataFlowCall`. */
|
||||
class DataFlowCallOption extends TDataFlowCallOption {
|
||||
string toString() {
|
||||
this = TDataFlowCallNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
|
||||
@@ -92,9 +92,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
|
||||
@@ -92,9 +92,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||
isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
||||
}
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
|
||||
Reference in New Issue
Block a user