Sync shared dataflow libraries

This commit is contained in:
Owen Mansel-Chan
2021-05-05 16:58:30 +01:00
parent 774717d2b8
commit daf73553f6
5 changed files with 635 additions and 301 deletions

View File

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

View File

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

View File

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

View File

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

View File

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