mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge branch 'main' into rdmarsh/cpp/use-taint-configuration-dtt
This commit is contained in:
@@ -6,6 +6,9 @@ import semmle.code.cpp.Location
|
||||
|
||||
/** A compiler-generated error, warning or remark. */
|
||||
class Diagnostic extends Locatable, @diagnostic {
|
||||
/** Gets the compilation that generated this diagnostic. */
|
||||
Compilation getCompilation() { diagnostic_for(underlyingElement(this), result, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the severity of the message, on a range from 1 to 5: 1=remark,
|
||||
* 2=warning, 3=discretionary error, 4=error, 5=catastrophic error.
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -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 lamba
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@@ -481,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) }
|
||||
|
||||
@@ -777,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
|
||||
@@ -791,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;
|
||||
@@ -812,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;
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -312,3 +312,14 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { none() }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -444,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
|
||||
@@ -471,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()
|
||||
)
|
||||
@@ -552,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)
|
||||
@@ -562,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)
|
||||
}
|
||||
|
||||
@@ -626,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
|
||||
@@ -864,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
|
||||
@@ -1045,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
|
||||
@@ -1059,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
|
||||
@@ -1114,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1182,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1240,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]
|
||||
@@ -1250,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 {
|
||||
@@ -1306,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))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1324,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
|
||||
@@ -1337,22 +1336,22 @@ private module LocalFlowBigStep {
|
||||
node1 != node2 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))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1459,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`.
|
||||
@@ -1470,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)
|
||||
}
|
||||
|
||||
@@ -1494,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
|
||||
@@ -1548,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)
|
||||
)
|
||||
}
|
||||
@@ -1627,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1675,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
|
||||
@@ -1689,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
|
||||
@@ -1744,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1812,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2125,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2141,8 +2152,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]
|
||||
@@ -2151,8 +2162,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]
|
||||
@@ -2167,6 +2178,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`.
|
||||
@@ -2178,7 +2196,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)
|
||||
}
|
||||
|
||||
@@ -2202,16 +2220,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
|
||||
@@ -2256,7 +2274,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)
|
||||
)
|
||||
}
|
||||
@@ -2335,7 +2353,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2383,9 +2401,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
|
||||
@@ -2397,9 +2415,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
|
||||
@@ -2452,9 +2470,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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2520,9 +2539,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))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2574,7 +2594,9 @@ 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 |
|
||||
@@ -2744,13 +2766,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)
|
||||
@@ -2758,7 +2780,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()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3055,7 +3077,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() {
|
||||
@@ -3067,7 +3089,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
|
||||
)
|
||||
}
|
||||
@@ -3298,7 +3320,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3310,7 +3332,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()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3433,8 +3455,8 @@ 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 |
|
||||
|
||||
@@ -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 lamba
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
@@ -481,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) }
|
||||
|
||||
@@ -777,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
|
||||
@@ -791,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;
|
||||
@@ -812,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;
|
||||
|
||||
@@ -548,3 +548,14 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -15,9 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction {
|
||||
Accept() { this.hasGlobalName(["accept", "accept4", "WSAAccept"]) }
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
bufParam = 1 and countParam = 2
|
||||
}
|
||||
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 1 }
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
|
||||
|
||||
@@ -46,8 +44,8 @@ private class Accept extends ArrayFunction, AliasFunction, TaintFunction, SideEf
|
||||
i = 1 and buffer = false
|
||||
}
|
||||
|
||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||
|
||||
// NOTE: The size parameter is a pointer to the size. So we can't implement `getParameterSizeIndex` for
|
||||
// this model.
|
||||
// NOTE: We implement thse two predicates as none because we can't model the low-level changes made to
|
||||
// the structure pointed to by the file-descriptor argument.
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
|
||||
Reference in New Issue
Block a user