зеркало из https://github.com/github/codeql.git
Merge branch 'main' into redsun82/swift-open-redirection
This commit is contained in:
Коммит
45c0c7fe6c
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -926,18 +926,46 @@ private module Cached {
|
||||||
TReturnCtxNoFlowThrough() or
|
TReturnCtxNoFlowThrough() or
|
||||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TTypedContentApprox =
|
||||||
|
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
|
||||||
|
exists(Content cont |
|
||||||
|
c = getContentApprox(cont) and
|
||||||
|
store(_, cont, _, _, t)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
TypedContent getATypedContent(TypedContentApprox c) {
|
||||||
|
exists(ContentApprox cls, DataFlowType t, Content cont |
|
||||||
|
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
|
||||||
|
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
|
||||||
|
cls = getContentApprox(cont)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFront =
|
newtype TAccessPathFront =
|
||||||
TFrontNil(DataFlowType t) or
|
TFrontNil(DataFlowType t) or
|
||||||
TFrontHead(TypedContent tc)
|
TFrontHead(TypedContent tc)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFront =
|
||||||
|
TApproxFrontNil(DataFlowType t) or
|
||||||
|
TApproxFrontHead(TypedContentApprox tc)
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFrontOption =
|
newtype TAccessPathFrontOption =
|
||||||
TAccessPathFrontNone() or
|
TAccessPathFrontNone() or
|
||||||
TAccessPathFrontSome(AccessPathFront apf)
|
TAccessPathFrontSome(AccessPathFront apf)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFrontOption =
|
||||||
|
TApproxAccessPathFrontNone() or
|
||||||
|
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An approximated `Content` tagged with the type of a containing object. */
|
||||||
|
class TypedContentApprox extends MkTypedContentApprox {
|
||||||
|
private ContentApprox c;
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
|
||||||
|
|
||||||
|
/** Gets a typed content approximated by this value. */
|
||||||
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the container type. */
|
||||||
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this approximated content. */
|
||||||
|
string toString() { result = c.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The front of an approximated access path. This is either a head or a nil.
|
||||||
|
*/
|
||||||
|
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
TypedContent getAHead() {
|
||||||
|
exists(TypedContentApprox cont |
|
||||||
|
this = TApproxFrontHead(cont) and
|
||||||
|
result = cont.getATypedContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
|
||||||
|
|
||||||
|
override string toString() { result = ppReprType(t) }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
|
||||||
|
private TypedContentApprox tc;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
|
||||||
|
|
||||||
|
override string toString() { result = tc.toString() }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An optional approximated access path front. */
|
||||||
|
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
|
||||||
|
string toString() {
|
||||||
|
this = TApproxAccessPathFrontNone() and result = "<none>"
|
||||||
|
or
|
||||||
|
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** A `Content` tagged with the type of a containing object. */
|
/** A `Content` tagged with the type of a containing object. */
|
||||||
class TypedContent extends MkTypedContent {
|
class TypedContent extends MkTypedContent {
|
||||||
private Content c;
|
private Content c;
|
||||||
|
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||||
|
|
||||||
abstract DataFlowType getType();
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract ApproxAccessPathFront toApprox();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|
||||||
override DataFlowType getType() { result = t }
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = false }
|
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
|
||||||
override DataFlowType getType() { result = tc.getContainerType() }
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = true }
|
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An optional access path front. */
|
/** An optional access path front. */
|
||||||
|
|
|
@ -260,4 +260,9 @@ module Consistency {
|
||||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||||
msg = "Parameter node with multiple positions."
|
msg = "Parameter node with multiple positions."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate uniqueContentApprox(Content c, string msg) {
|
||||||
|
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
|
||||||
|
msg = "Non-unique content approximation."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -551,6 +551,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||||
*/
|
*/
|
||||||
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
||||||
|
|
||||||
|
/** An approximated `Content`. */
|
||||||
|
class ContentApprox = Unit;
|
||||||
|
|
||||||
|
/** Gets an approximated value for content `c`. */
|
||||||
|
pragma[inline]
|
||||||
|
ContentApprox getContentApprox(Content c) { any() }
|
||||||
|
|
||||||
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
||||||
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||||
// The rules for whether an IR argument gets a post-update node are too
|
// The rules for whether an IR argument gets a post-update node are too
|
||||||
|
|
|
@ -292,12 +292,8 @@ module SemanticExprConfig {
|
||||||
final Location getLocation() { result = super.getLocation() }
|
final Location getLocation() { result = super.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ValueNumberBound extends Bound {
|
private class ValueNumberBound extends Bound instanceof IRBound::ValueNumberBound {
|
||||||
IRBound::ValueNumberBound bound;
|
override string toString() { result = IRBound::ValueNumberBound.super.toString() }
|
||||||
|
|
||||||
ValueNumberBound() { bound = this }
|
|
||||||
|
|
||||||
override string toString() { result = bound.toString() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
||||||
|
|
|
@ -33,23 +33,15 @@ abstract private class FlowSignDef extends SignDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||||
private class ExplicitSignDef extends FlowSignDef {
|
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||||
SemSsaExplicitUpdate update;
|
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
||||||
|
|
||||||
ExplicitSignDef() { update = this }
|
|
||||||
|
|
||||||
final override Sign getSign() { result = semExprSign(update.getSourceExpr()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||||
private class PhiSignDef extends FlowSignDef {
|
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||||
SemSsaPhiNode phi;
|
|
||||||
|
|
||||||
PhiSignDef() { phi = this }
|
|
||||||
|
|
||||||
final override Sign getSign() {
|
final override Sign getSign() {
|
||||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||||
edge.phiInput(phi, inp) and
|
edge.phiInput(this, inp) and
|
||||||
result = semSsaSign(inp, edge)
|
result = semSsaSign(inp, edge)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,11 +397,8 @@ private int lengthInBase16(float f) {
|
||||||
/**
|
/**
|
||||||
* A class to represent format strings that occur as arguments to invocations of formatting functions.
|
* A class to represent format strings that occur as arguments to invocations of formatting functions.
|
||||||
*/
|
*/
|
||||||
class FormatLiteral extends Literal {
|
class FormatLiteral extends Literal instanceof StringLiteral {
|
||||||
FormatLiteral() {
|
FormatLiteral() { exists(FormattingFunctionCall ffc | ffc.getFormat() = this) }
|
||||||
exists(FormattingFunctionCall ffc | ffc.getFormat() = this) and
|
|
||||||
this instanceof StringLiteral
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function call where this format string is used.
|
* Gets the function call where this format string is used.
|
||||||
|
|
|
@ -30,15 +30,12 @@ abstract class ScanfFunction extends Function {
|
||||||
/**
|
/**
|
||||||
* The standard function `scanf` (and variations).
|
* The standard function `scanf` (and variations).
|
||||||
*/
|
*/
|
||||||
class Scanf extends ScanfFunction {
|
class Scanf extends ScanfFunction instanceof TopLevelFunction {
|
||||||
Scanf() {
|
Scanf() {
|
||||||
this instanceof TopLevelFunction and
|
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
|
||||||
(
|
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
|
||||||
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
|
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
|
||||||
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
|
this.hasGlobalName("_wscanf_l")
|
||||||
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
|
|
||||||
this.hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getInputParameterIndex() { none() }
|
override int getInputParameterIndex() { none() }
|
||||||
|
@ -49,15 +46,12 @@ class Scanf extends ScanfFunction {
|
||||||
/**
|
/**
|
||||||
* The standard function `fscanf` (and variations).
|
* The standard function `fscanf` (and variations).
|
||||||
*/
|
*/
|
||||||
class Fscanf extends ScanfFunction {
|
class Fscanf extends ScanfFunction instanceof TopLevelFunction {
|
||||||
Fscanf() {
|
Fscanf() {
|
||||||
this instanceof TopLevelFunction and
|
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
|
||||||
(
|
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
|
||||||
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
|
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
|
||||||
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
|
this.hasGlobalName("_fwscanf_l")
|
||||||
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
|
|
||||||
this.hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getInputParameterIndex() { result = 0 }
|
override int getInputParameterIndex() { result = 0 }
|
||||||
|
@ -68,15 +62,12 @@ class Fscanf extends ScanfFunction {
|
||||||
/**
|
/**
|
||||||
* The standard function `sscanf` (and variations).
|
* The standard function `sscanf` (and variations).
|
||||||
*/
|
*/
|
||||||
class Sscanf extends ScanfFunction {
|
class Sscanf extends ScanfFunction instanceof TopLevelFunction {
|
||||||
Sscanf() {
|
Sscanf() {
|
||||||
this instanceof TopLevelFunction and
|
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
|
||||||
(
|
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
|
||||||
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
|
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
|
||||||
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
|
this.hasGlobalName("_swscanf_l")
|
||||||
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
|
|
||||||
this.hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getInputParameterIndex() { result = 0 }
|
override int getInputParameterIndex() { result = 0 }
|
||||||
|
@ -87,17 +78,12 @@ class Sscanf extends ScanfFunction {
|
||||||
/**
|
/**
|
||||||
* The standard(ish) function `snscanf` (and variations).
|
* The standard(ish) function `snscanf` (and variations).
|
||||||
*/
|
*/
|
||||||
class Snscanf extends ScanfFunction {
|
class Snscanf extends ScanfFunction instanceof TopLevelFunction {
|
||||||
Snscanf() {
|
Snscanf() {
|
||||||
this instanceof TopLevelFunction and
|
this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
|
||||||
(
|
this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
|
||||||
this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
|
this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
|
||||||
this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
|
this.hasGlobalName("_snwscanf_l")
|
||||||
this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
|
|
||||||
this.hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...)
|
|
||||||
// note that the max_amount is not a limit on the output length, it's an input length
|
|
||||||
// limit used with non null-terminated strings.
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getInputParameterIndex() { result = 0 }
|
override int getInputParameterIndex() { result = 0 }
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -926,18 +926,46 @@ private module Cached {
|
||||||
TReturnCtxNoFlowThrough() or
|
TReturnCtxNoFlowThrough() or
|
||||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TTypedContentApprox =
|
||||||
|
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
|
||||||
|
exists(Content cont |
|
||||||
|
c = getContentApprox(cont) and
|
||||||
|
store(_, cont, _, _, t)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
TypedContent getATypedContent(TypedContentApprox c) {
|
||||||
|
exists(ContentApprox cls, DataFlowType t, Content cont |
|
||||||
|
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
|
||||||
|
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
|
||||||
|
cls = getContentApprox(cont)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFront =
|
newtype TAccessPathFront =
|
||||||
TFrontNil(DataFlowType t) or
|
TFrontNil(DataFlowType t) or
|
||||||
TFrontHead(TypedContent tc)
|
TFrontHead(TypedContent tc)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFront =
|
||||||
|
TApproxFrontNil(DataFlowType t) or
|
||||||
|
TApproxFrontHead(TypedContentApprox tc)
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFrontOption =
|
newtype TAccessPathFrontOption =
|
||||||
TAccessPathFrontNone() or
|
TAccessPathFrontNone() or
|
||||||
TAccessPathFrontSome(AccessPathFront apf)
|
TAccessPathFrontSome(AccessPathFront apf)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFrontOption =
|
||||||
|
TApproxAccessPathFrontNone() or
|
||||||
|
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An approximated `Content` tagged with the type of a containing object. */
|
||||||
|
class TypedContentApprox extends MkTypedContentApprox {
|
||||||
|
private ContentApprox c;
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
|
||||||
|
|
||||||
|
/** Gets a typed content approximated by this value. */
|
||||||
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the container type. */
|
||||||
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this approximated content. */
|
||||||
|
string toString() { result = c.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The front of an approximated access path. This is either a head or a nil.
|
||||||
|
*/
|
||||||
|
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
TypedContent getAHead() {
|
||||||
|
exists(TypedContentApprox cont |
|
||||||
|
this = TApproxFrontHead(cont) and
|
||||||
|
result = cont.getATypedContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
|
||||||
|
|
||||||
|
override string toString() { result = ppReprType(t) }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
|
||||||
|
private TypedContentApprox tc;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
|
||||||
|
|
||||||
|
override string toString() { result = tc.toString() }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An optional approximated access path front. */
|
||||||
|
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
|
||||||
|
string toString() {
|
||||||
|
this = TApproxAccessPathFrontNone() and result = "<none>"
|
||||||
|
or
|
||||||
|
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** A `Content` tagged with the type of a containing object. */
|
/** A `Content` tagged with the type of a containing object. */
|
||||||
class TypedContent extends MkTypedContent {
|
class TypedContent extends MkTypedContent {
|
||||||
private Content c;
|
private Content c;
|
||||||
|
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||||
|
|
||||||
abstract DataFlowType getType();
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract ApproxAccessPathFront toApprox();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|
||||||
override DataFlowType getType() { result = t }
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = false }
|
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
|
||||||
override DataFlowType getType() { result = tc.getContainerType() }
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = true }
|
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An optional access path front. */
|
/** An optional access path front. */
|
||||||
|
|
|
@ -260,4 +260,9 @@ module Consistency {
|
||||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||||
msg = "Parameter node with multiple positions."
|
msg = "Parameter node with multiple positions."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate uniqueContentApprox(Content c, string msg) {
|
||||||
|
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
|
||||||
|
msg = "Non-unique content approximation."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -296,6 +296,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||||
*/
|
*/
|
||||||
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
||||||
|
|
||||||
|
/** An approximated `Content`. */
|
||||||
|
class ContentApprox = Unit;
|
||||||
|
|
||||||
|
/** Gets an approximated value for content `c`. */
|
||||||
|
pragma[inline]
|
||||||
|
ContentApprox getContentApprox(Content c) { any() }
|
||||||
|
|
||||||
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
||||||
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||||
// Is the null pointer (or something that's not really a pointer)
|
// Is the null pointer (or something that's not really a pointer)
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -926,18 +926,46 @@ private module Cached {
|
||||||
TReturnCtxNoFlowThrough() or
|
TReturnCtxNoFlowThrough() or
|
||||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TTypedContentApprox =
|
||||||
|
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
|
||||||
|
exists(Content cont |
|
||||||
|
c = getContentApprox(cont) and
|
||||||
|
store(_, cont, _, _, t)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
TypedContent getATypedContent(TypedContentApprox c) {
|
||||||
|
exists(ContentApprox cls, DataFlowType t, Content cont |
|
||||||
|
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
|
||||||
|
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
|
||||||
|
cls = getContentApprox(cont)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFront =
|
newtype TAccessPathFront =
|
||||||
TFrontNil(DataFlowType t) or
|
TFrontNil(DataFlowType t) or
|
||||||
TFrontHead(TypedContent tc)
|
TFrontHead(TypedContent tc)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFront =
|
||||||
|
TApproxFrontNil(DataFlowType t) or
|
||||||
|
TApproxFrontHead(TypedContentApprox tc)
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFrontOption =
|
newtype TAccessPathFrontOption =
|
||||||
TAccessPathFrontNone() or
|
TAccessPathFrontNone() or
|
||||||
TAccessPathFrontSome(AccessPathFront apf)
|
TAccessPathFrontSome(AccessPathFront apf)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFrontOption =
|
||||||
|
TApproxAccessPathFrontNone() or
|
||||||
|
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An approximated `Content` tagged with the type of a containing object. */
|
||||||
|
class TypedContentApprox extends MkTypedContentApprox {
|
||||||
|
private ContentApprox c;
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
|
||||||
|
|
||||||
|
/** Gets a typed content approximated by this value. */
|
||||||
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the container type. */
|
||||||
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this approximated content. */
|
||||||
|
string toString() { result = c.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The front of an approximated access path. This is either a head or a nil.
|
||||||
|
*/
|
||||||
|
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
TypedContent getAHead() {
|
||||||
|
exists(TypedContentApprox cont |
|
||||||
|
this = TApproxFrontHead(cont) and
|
||||||
|
result = cont.getATypedContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
|
||||||
|
|
||||||
|
override string toString() { result = ppReprType(t) }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
|
||||||
|
private TypedContentApprox tc;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
|
||||||
|
|
||||||
|
override string toString() { result = tc.toString() }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An optional approximated access path front. */
|
||||||
|
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
|
||||||
|
string toString() {
|
||||||
|
this = TApproxAccessPathFrontNone() and result = "<none>"
|
||||||
|
or
|
||||||
|
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** A `Content` tagged with the type of a containing object. */
|
/** A `Content` tagged with the type of a containing object. */
|
||||||
class TypedContent extends MkTypedContent {
|
class TypedContent extends MkTypedContent {
|
||||||
private Content c;
|
private Content c;
|
||||||
|
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||||
|
|
||||||
abstract DataFlowType getType();
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract ApproxAccessPathFront toApprox();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|
||||||
override DataFlowType getType() { result = t }
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = false }
|
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
|
||||||
override DataFlowType getType() { result = tc.getContainerType() }
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = true }
|
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An optional access path front. */
|
/** An optional access path front. */
|
||||||
|
|
|
@ -260,4 +260,9 @@ module Consistency {
|
||||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||||
msg = "Parameter node with multiple positions."
|
msg = "Parameter node with multiple positions."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate uniqueContentApprox(Content c, string msg) {
|
||||||
|
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
|
||||||
|
msg = "Non-unique content approximation."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,6 +400,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||||
*/
|
*/
|
||||||
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
||||||
|
|
||||||
|
/** An approximated `Content`. */
|
||||||
|
class ContentApprox = Unit;
|
||||||
|
|
||||||
|
/** Gets an approximated value for content `c`. */
|
||||||
|
pragma[inline]
|
||||||
|
ContentApprox getContentApprox(Content c) { any() }
|
||||||
|
|
||||||
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
|
||||||
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||||
// The rules for whether an IR argument gets a post-update node are too
|
// The rules for whether an IR argument gets a post-update node are too
|
||||||
|
|
|
@ -66,9 +66,7 @@ class ElseDirective extends Directive {
|
||||||
override predicate mismatched() { depth() < 1 }
|
override predicate mismatched() { depth() < 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
class EndifDirective extends Directive {
|
class EndifDirective extends Directive instanceof PreprocessorEndif {
|
||||||
EndifDirective() { this instanceof PreprocessorEndif }
|
|
||||||
|
|
||||||
override int depthChange() { result = -1 }
|
override int depthChange() { result = -1 }
|
||||||
|
|
||||||
override predicate mismatched() { depth() < 0 }
|
override predicate mismatched() { depth() < 0 }
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.FunctionWithWrappers
|
import semmle.code.cpp.security.FunctionWithWrappers
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.FlowSources
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
@ -47,12 +47,6 @@ class FileFunction extends FunctionWithWrappers {
|
||||||
override predicate interestingArg(int arg) { arg = 0 }
|
override predicate interestingArg(int arg) { arg = 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr asSourceExpr(DataFlow::Node node) {
|
|
||||||
result = node.asConvertedExpr()
|
|
||||||
or
|
|
||||||
result = node.asDefiningArgument()
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr asSinkExpr(DataFlow::Node node) {
|
Expr asSinkExpr(DataFlow::Node node) {
|
||||||
result =
|
result =
|
||||||
node.asOperand()
|
node.asOperand()
|
||||||
|
@ -89,7 +83,7 @@ predicate hasUpperBoundsCheck(Variable var) {
|
||||||
class TaintedPathConfiguration extends TaintTracking::Configuration {
|
class TaintedPathConfiguration extends TaintTracking::Configuration {
|
||||||
TaintedPathConfiguration() { this = "TaintedPathConfiguration" }
|
TaintedPathConfiguration() { this = "TaintedPathConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node) { isUserInput(asSourceExpr(node), _) }
|
override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) {
|
override predicate isSink(DataFlow::Node node) {
|
||||||
exists(FileFunction fileFunction |
|
exists(FileFunction fileFunction |
|
||||||
|
@ -108,31 +102,16 @@ class TaintedPathConfiguration extends TaintTracking::Configuration {
|
||||||
hasUpperBoundsCheck(checkedVar)
|
hasUpperBoundsCheck(checkedVar)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasFilteredFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
|
|
||||||
this.hasFlowPath(source, sink) and
|
|
||||||
// The use of `isUserInput` in `isSink` in combination with `asSourceExpr` causes
|
|
||||||
// duplicate results. Filter these duplicates. The proper solution is to switch to
|
|
||||||
// using `LocalFlowSource` and `RemoteFlowSource`, but this currently only supports
|
|
||||||
// a subset of the cases supported by `isUserInput`.
|
|
||||||
not exists(DataFlow::PathNode source2 |
|
|
||||||
this.hasFlowPath(source2, sink) and
|
|
||||||
asSourceExpr(source.getNode()) = asSourceExpr(source2.getNode())
|
|
||||||
|
|
|
||||||
not exists(source.getNode().asConvertedExpr()) and exists(source2.getNode().asConvertedExpr())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
FileFunction fileFunction, Expr taintedArg, Expr taintSource, TaintedPathConfiguration cfg,
|
FileFunction fileFunction, Expr taintedArg, FlowSource taintSource, TaintedPathConfiguration cfg,
|
||||||
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string taintCause, string callChain
|
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string callChain
|
||||||
where
|
where
|
||||||
taintedArg = asSinkExpr(sinkNode.getNode()) and
|
taintedArg = asSinkExpr(sinkNode.getNode()) and
|
||||||
fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and
|
fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and
|
||||||
cfg.hasFilteredFlowPath(sourceNode, sinkNode) and
|
cfg.hasFlowPath(sourceNode, sinkNode) and
|
||||||
taintSource = asSourceExpr(sourceNode.getNode()) and
|
taintSource = sourceNode.getNode()
|
||||||
isUserInput(taintSource, taintCause)
|
|
||||||
select taintedArg, sourceNode, sinkNode,
|
select taintedArg, sourceNode, sinkNode,
|
||||||
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
|
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
|
||||||
taintSource, "user input (" + taintCause + ")"
|
taintSource, "user input (" + taintSource.getSourceType() + ")"
|
||||||
|
|
|
@ -95,3 +95,4 @@ postWithInFlow
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -639,3 +639,4 @@ postWithInFlow
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -160,3 +160,4 @@ postWithInFlow
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -1328,3 +1328,4 @@ postWithInFlow
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -129,3 +129,4 @@ postWithInFlow
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -2717,3 +2717,4 @@ uniqueParameterNodeAtPosition
|
||||||
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:735:22:735:22 | *s | Parameters with overlapping positions. |
|
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:735:22:735:22 | *s | Parameters with overlapping positions. |
|
||||||
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:738:24:738:24 | *e | Parameters with overlapping positions. |
|
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:738:24:738:24 | *e | Parameters with overlapping positions. |
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
uniqueContentApprox
|
||||||
|
|
|
@ -3,10 +3,8 @@ import Metrics.Dependencies.ExternalDependencies
|
||||||
/**
|
/**
|
||||||
* Count directories as libraries for testing purposes.
|
* Count directories as libraries for testing purposes.
|
||||||
*/
|
*/
|
||||||
class TestPackage extends LibraryElement {
|
class TestPackage extends LibraryElement instanceof Folder {
|
||||||
TestPackage() { this instanceof Folder }
|
override string getName() { result = super.getBaseName() }
|
||||||
|
|
||||||
override string getName() { result = this.(Folder).getBaseName() }
|
|
||||||
|
|
||||||
override string getVersion() { result = "1.0" }
|
override string getVersion() { result = "1.0" }
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,4 @@ nodes
|
||||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
|
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) |
|
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | user input (string read by fgets) |
|
||||||
|
|
|
@ -2,7 +2,6 @@ edges
|
||||||
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection |
|
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection |
|
||||||
| test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection |
|
| test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection |
|
||||||
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection |
|
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection |
|
||||||
| test.c:43:17:43:24 | fileName | test.c:44:11:44:18 | fileName indirection |
|
|
||||||
| test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection |
|
| test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection |
|
||||||
nodes
|
nodes
|
||||||
| test.c:9:23:9:26 | argv | semmle.label | argv |
|
| test.c:9:23:9:26 | argv | semmle.label | argv |
|
||||||
|
@ -11,12 +10,11 @@ nodes
|
||||||
| test.c:32:11:32:18 | fileName indirection | semmle.label | fileName indirection |
|
| test.c:32:11:32:18 | fileName indirection | semmle.label | fileName indirection |
|
||||||
| test.c:37:17:37:24 | scanf output argument | semmle.label | scanf output argument |
|
| test.c:37:17:37:24 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| test.c:38:11:38:18 | fileName indirection | semmle.label | fileName indirection |
|
| test.c:38:11:38:18 | fileName indirection | semmle.label | fileName indirection |
|
||||||
| test.c:43:17:43:24 | fileName | semmle.label | fileName |
|
|
||||||
| test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument |
|
| test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument |
|
||||||
| test.c:44:11:44:18 | fileName indirection | semmle.label | fileName indirection |
|
| test.c:44:11:44:18 | fileName indirection | semmle.label | fileName indirection |
|
||||||
subpaths
|
subpaths
|
||||||
#select
|
#select
|
||||||
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (argv) |
|
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (a command-line argument) |
|
||||||
| test.c:32:11:32:18 | fileName | test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:31:22:31:25 | argv | user input (argv) |
|
| test.c:32:11:32:18 | fileName | test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:31:22:31:25 | argv | user input (a command-line argument) |
|
||||||
| test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | fileName | user input (scanf) |
|
| test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | scanf output argument | user input (value read by scanf) |
|
||||||
| test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | fileName | test.c:44:11:44:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | fileName | user input (scanf) |
|
| test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | scanf output argument | user input (value read by scanf) |
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:local,summary:taint,summary:value
|
package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:local,source:remote,summary:taint,summary:value
|
||||||
Dapper,55,,,,,,,,,,55,,,,,
|
Dapper,55,,,,,,,,,,55,,,,,,
|
||||||
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,7,
|
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,7,
|
||||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,
|
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,,
|
||||||
Microsoft.CSharp,,,24,,,,,,,,,,,,24,
|
Microsoft.CSharp,,,24,,,,,,,,,,,,,24,
|
||||||
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,
|
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,,
|
||||||
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,15,
|
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,15,
|
||||||
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1
|
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,,45,1
|
||||||
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3
|
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,,80,3
|
||||||
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62,
|
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,,62,
|
||||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12,
|
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,12,
|
||||||
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16,
|
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,,16,
|
||||||
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2
|
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,,13,2
|
||||||
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1
|
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,,16,1
|
||||||
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10,
|
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,10,
|
||||||
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,37,
|
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,,37,
|
||||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,8,
|
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,8,
|
||||||
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,63,
|
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,,63,
|
||||||
Microsoft.Interop,,,27,,,,,,,,,,,,27,
|
Microsoft.Interop,,,27,,,,,,,,,,,,,27,
|
||||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,1,
|
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,1,
|
||||||
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,4,
|
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,,4,
|
||||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,5,5
|
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,5,5
|
||||||
Microsoft.Win32,,,8,,,,,,,,,,,,8,
|
Microsoft.Win32,,,8,,,,,,,,,,,,,8,
|
||||||
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,
|
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,,
|
||||||
Newtonsoft.Json,,,91,,,,,,,,,,,,73,18
|
Newtonsoft.Json,,,91,,,,,,,,,,,,,73,18
|
||||||
ServiceStack,194,,7,27,,,,,,75,92,,,,7,
|
ServiceStack,194,,7,27,,,,,,75,92,,,,,7,
|
||||||
System,65,4,12142,,8,8,9,,4,,33,3,1,3,10151,1991
|
System,65,8,12154,,8,8,9,,4,,33,3,1,3,4,10163,1991
|
||||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,
|
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,
|
||||||
|
|
|
|
@ -8,7 +8,7 @@ C# framework & library support
|
||||||
|
|
||||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||||
System,"``System.*``, ``System``",4,12142,65,7
|
System,"``System.*``, ``System``",8,12154,65,7
|
||||||
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138,
|
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138,
|
||||||
Totals,,4,12705,397,7
|
Totals,,8,12717,397,7
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* Added tcp/upd sockets as taint sources.
|
|
@ -57,7 +57,19 @@ extensions:
|
||||||
- ["System.IO", "Stream", True, "Write", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
- ["System.IO", "Stream", True, "Write", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
||||||
- ["System.IO", "Stream", False, "WriteAsync", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
- ["System.IO", "Stream", False, "WriteAsync", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
||||||
- ["System.IO", "Stream", True, "WriteAsync", "(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
- ["System.IO", "Stream", True, "WriteAsync", "(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
|
||||||
- ["System.IO", "StreamReader", False, "StreamReader", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean,System.IO.FileStreamOptions)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean,System.Int32)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.IO.FileStreamOptions)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
|
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
- ["System.IO", "StringReader", False, "StringReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
- ["System.IO", "StringReader", False, "StringReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
|
||||||
- ["System.IO", "TextReader", True, "Read", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
- ["System.IO", "TextReader", True, "Read", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
||||||
- ["System.IO", "TextReader", True, "Read", "(System.Char[],System.Int32,System.Int32)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
- ["System.IO", "TextReader", True, "Read", "(System.Char[],System.Int32,System.Int32)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
extensions:
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/csharp-all
|
||||||
|
extensible: extSourceModel
|
||||||
|
data:
|
||||||
|
- ["System.Net.Sockets", "TcpClient", False, "GetStream", "", "", "ReturnValue", "remote", "manual"]
|
||||||
|
- ["System.Net.Sockets", "UpdClient", False, "EndReceive", "", "", "ReturnValue", "remote", "manual"]
|
||||||
|
- ["System.Net.Sockets", "UpdClient", False, "Receive", "", "", "ReturnValue", "remote", "manual"]
|
||||||
|
- ["System.Net.Sockets", "UpdClient", False, "ReceiveAsync", "", "", "ReturnValue", "remote", "manual"]
|
||||||
- addsTo:
|
- addsTo:
|
||||||
pack: codeql/csharp-all
|
pack: codeql/csharp-all
|
||||||
extensible: extSummaryModel
|
extensible: extSummaryModel
|
||||||
|
|
|
@ -358,6 +358,9 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @
|
||||||
if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1)
|
if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if this is a constructor without parameters. */
|
||||||
|
predicate isParameterless() { this.getNumberOfParameters() = 0 }
|
||||||
|
|
||||||
override string getUndecoratedName() { result = ".ctor" }
|
override string getUndecoratedName() { result = ".ctor" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,40 +368,32 @@ private Stmt getAnAssertingStmt(Assertion a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A method that forwards to a Boolean assertion method. */
|
/** A method that forwards to a Boolean assertion method. */
|
||||||
class ForwarderBooleanAssertMethod extends BooleanAssertMethod {
|
class ForwarderBooleanAssertMethod extends BooleanAssertMethod instanceof ForwarderAssertMethod {
|
||||||
private ForwarderAssertMethod forwarder;
|
|
||||||
private BooleanAssertMethod underlying;
|
private BooleanAssertMethod underlying;
|
||||||
|
|
||||||
ForwarderBooleanAssertMethod() {
|
ForwarderBooleanAssertMethod() { underlying = super.getUnderlyingAssertMethod() }
|
||||||
forwarder = this and
|
|
||||||
underlying = forwarder.getUnderlyingAssertMethod()
|
|
||||||
}
|
|
||||||
|
|
||||||
override int getAnAssertionIndex(boolean b) {
|
override int getAnAssertionIndex(boolean b) {
|
||||||
forwarder.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
|
super.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
override AssertionFailure getAssertionFailure(int i) {
|
override AssertionFailure getAssertionFailure(int i) {
|
||||||
result = underlying.getAssertionFailure(forwarder.getAForwarderAssertionIndex(i))
|
result = underlying.getAssertionFailure(super.getAForwarderAssertionIndex(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A method that forwards to a nullness assertion method. */
|
/** A method that forwards to a nullness assertion method. */
|
||||||
class ForwarderNullnessAssertMethod extends NullnessAssertMethod {
|
class ForwarderNullnessAssertMethod extends NullnessAssertMethod instanceof ForwarderAssertMethod {
|
||||||
private ForwarderAssertMethod forwarder;
|
|
||||||
private NullnessAssertMethod underlying;
|
private NullnessAssertMethod underlying;
|
||||||
|
|
||||||
ForwarderNullnessAssertMethod() {
|
ForwarderNullnessAssertMethod() { underlying = super.getUnderlyingAssertMethod() }
|
||||||
forwarder = this and
|
|
||||||
underlying = forwarder.getUnderlyingAssertMethod()
|
|
||||||
}
|
|
||||||
|
|
||||||
override int getAnAssertionIndex(boolean b) {
|
override int getAnAssertionIndex(boolean b) {
|
||||||
forwarder.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
|
super.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
override AssertionFailure getAssertionFailure(int i) {
|
override AssertionFailure getAssertionFailure(int i) {
|
||||||
result = underlying.getAssertionFailure(forwarder.getAForwarderAssertionIndex(i))
|
result = underlying.getAssertionFailure(super.getAForwarderAssertionIndex(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -338,7 +338,7 @@ module ModelValidation {
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) |
|
exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) |
|
||||||
not kind = ["local", "file"] and
|
not kind = ["local", "remote", "file"] and
|
||||||
result = "Invalid kind \"" + kind + "\" in source model."
|
result = "Invalid kind \"" + kind + "\" in source model."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,18 +222,14 @@ module ContentDataFlow {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ConfigurationAdapter extends DF::Configuration {
|
private class ConfigurationAdapter extends DF::Configuration instanceof Configuration {
|
||||||
private Configuration c;
|
|
||||||
|
|
||||||
ConfigurationAdapter() { this = c }
|
|
||||||
|
|
||||||
final override predicate isSource(Node source, DF::FlowState state) {
|
final override predicate isSource(Node source, DF::FlowState state) {
|
||||||
c.isSource(source) and
|
Configuration.super.isSource(source) and
|
||||||
state.(InitState).decode(true)
|
state.(InitState).decode(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate isSink(Node sink, DF::FlowState state) {
|
final override predicate isSink(Node sink, DF::FlowState state) {
|
||||||
c.isSink(sink) and
|
Configuration.super.isSink(sink) and
|
||||||
(
|
(
|
||||||
state instanceof InitState or
|
state instanceof InitState or
|
||||||
state instanceof StoreState or
|
state instanceof StoreState or
|
||||||
|
@ -249,9 +245,9 @@ module ContentDataFlow {
|
||||||
additionalStep(node1, state1, node2, state2, this)
|
additionalStep(node1, state1, node2, state2, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate isBarrier(Node node) { c.isBarrier(node) }
|
final override predicate isBarrier(Node node) { Configuration.super.isBarrier(node) }
|
||||||
|
|
||||||
final override FlowFeature getAFeature() { result = c.getAFeature() }
|
final override FlowFeature getAFeature() { result = Configuration.super.getAFeature() }
|
||||||
|
|
||||||
// needed to record reads/stores inside summarized callables
|
// needed to record reads/stores inside summarized callables
|
||||||
final override predicate includeHiddenNodes() { any() }
|
final override predicate includeHiddenNodes() { any() }
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -926,18 +926,46 @@ private module Cached {
|
||||||
TReturnCtxNoFlowThrough() or
|
TReturnCtxNoFlowThrough() or
|
||||||
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TTypedContentApprox =
|
||||||
|
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
|
||||||
|
exists(Content cont |
|
||||||
|
c = getContentApprox(cont) and
|
||||||
|
store(_, cont, _, _, t)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||||
|
|
||||||
|
cached
|
||||||
|
TypedContent getATypedContent(TypedContentApprox c) {
|
||||||
|
exists(ContentApprox cls, DataFlowType t, Content cont |
|
||||||
|
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
|
||||||
|
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
|
||||||
|
cls = getContentApprox(cont)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFront =
|
newtype TAccessPathFront =
|
||||||
TFrontNil(DataFlowType t) or
|
TFrontNil(DataFlowType t) or
|
||||||
TFrontHead(TypedContent tc)
|
TFrontHead(TypedContent tc)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFront =
|
||||||
|
TApproxFrontNil(DataFlowType t) or
|
||||||
|
TApproxFrontHead(TypedContentApprox tc)
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TAccessPathFrontOption =
|
newtype TAccessPathFrontOption =
|
||||||
TAccessPathFrontNone() or
|
TAccessPathFrontNone() or
|
||||||
TAccessPathFrontSome(AccessPathFront apf)
|
TAccessPathFrontSome(AccessPathFront apf)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TApproxAccessPathFrontOption =
|
||||||
|
TApproxAccessPathFrontNone() or
|
||||||
|
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An approximated `Content` tagged with the type of a containing object. */
|
||||||
|
class TypedContentApprox extends MkTypedContentApprox {
|
||||||
|
private ContentApprox c;
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
|
||||||
|
|
||||||
|
/** Gets a typed content approximated by this value. */
|
||||||
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the container type. */
|
||||||
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this approximated content. */
|
||||||
|
string toString() { result = c.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The front of an approximated access path. This is either a head or a nil.
|
||||||
|
*/
|
||||||
|
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
TypedContent getAHead() {
|
||||||
|
exists(TypedContentApprox cont |
|
||||||
|
this = TApproxFrontHead(cont) and
|
||||||
|
result = cont.getATypedContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
|
||||||
|
private DataFlowType t;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
|
||||||
|
|
||||||
|
override string toString() { result = ppReprType(t) }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
|
||||||
|
private TypedContentApprox tc;
|
||||||
|
|
||||||
|
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
|
||||||
|
|
||||||
|
override string toString() { result = tc.toString() }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
|
override boolean toBoolNonEmpty() { result = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An optional approximated access path front. */
|
||||||
|
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
|
||||||
|
string toString() {
|
||||||
|
this = TApproxAccessPathFrontNone() and result = "<none>"
|
||||||
|
or
|
||||||
|
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** A `Content` tagged with the type of a containing object. */
|
/** A `Content` tagged with the type of a containing object. */
|
||||||
class TypedContent extends MkTypedContent {
|
class TypedContent extends MkTypedContent {
|
||||||
private Content c;
|
private Content c;
|
||||||
|
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||||
|
|
||||||
abstract DataFlowType getType();
|
abstract DataFlowType getType();
|
||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract ApproxAccessPathFront toApprox();
|
||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|
||||||
override DataFlowType getType() { result = t }
|
override DataFlowType getType() { result = t }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = false }
|
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
|
||||||
|
|
||||||
override DataFlowType getType() { result = tc.getContainerType() }
|
override DataFlowType getType() { result = tc.getContainerType() }
|
||||||
|
|
||||||
override boolean toBoolNonEmpty() { result = true }
|
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An optional access path front. */
|
/** An optional access path front. */
|
||||||
|
|
|
@ -260,4 +260,9 @@ module Consistency {
|
||||||
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
|
||||||
msg = "Parameter node with multiple positions."
|
msg = "Parameter node with multiple positions."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query predicate uniqueContentApprox(Content c, string msg) {
|
||||||
|
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
|
||||||
|
msg = "Non-unique content approximation."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
|
|
||||||
* kind `kind` is allowed.
|
|
||||||
*
|
|
||||||
* We don't expect a parameter to return stored in itself, unless
|
|
||||||
* explicitly allowed
|
|
||||||
*/
|
|
||||||
bindingset[c, pos, kind]
|
|
||||||
private predicate parameterFlowThroughAllowed(
|
|
||||||
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
|
|
||||||
) {
|
|
||||||
exists(ParamNodeEx p |
|
|
||||||
p.isParameterOf(c, pos) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private module Stage1 implements StageSig {
|
private module Stage1 implements StageSig {
|
||||||
class Ap = Unit;
|
class Ap = Unit;
|
||||||
|
|
||||||
|
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, config) and
|
||||||
|
exists(ap)
|
||||||
|
}
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||||
|
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
) {
|
||||||
throughFlowNodeCand(ret, config) and
|
throughFlowNodeCand(ret, config) and
|
||||||
kind = ret.getKind()
|
kind = ret.getKind() and
|
||||||
|
exists(argAp) and
|
||||||
|
exists(ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -1189,6 +1182,8 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate revFlow(NodeEx node, Configuration config);
|
predicate revFlow(NodeEx node, Configuration config);
|
||||||
|
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
|
||||||
|
|
||||||
bindingset[node, state, config]
|
bindingset[node, state, config]
|
||||||
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
|
||||||
|
|
||||||
|
@ -1196,7 +1191,9 @@ private signature module StageSig {
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
|
||||||
|
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
|
predicate returnMayFlowThrough(
|
||||||
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
|
);
|
||||||
|
|
||||||
predicate storeStepCand(
|
predicate storeStepCand(
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
|
||||||
|
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
|
||||||
import Param
|
import Param
|
||||||
|
|
||||||
/* Begin: Stage logic. */
|
/* Begin: Stage logic. */
|
||||||
bindingset[result, apa]
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
private ApApprox unbindApa(ApApprox apa) {
|
pragma[nomagic]
|
||||||
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
|
private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
|
||||||
|
PrevStage::revFlowAp(node, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallApa(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallApa(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
NodeEx out, boolean allowsFieldFlow, Configuration config
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
|
exists(ReturnKindExt kind |
|
||||||
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
|
||||||
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
|
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
|
||||||
matchesCall(ccc, call) and
|
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
|
||||||
c = ret.getEnclosingCallable()
|
matchesCall(ccc, call)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
|
||||||
* corresponding parameter position and access path of that argument, respectively.
|
* corresponding parameter position and access path of that argument, respectively.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
additional predicate fwdFlow(
|
||||||
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
|
||||||
|
PrevStage::revFlow(node, state, apa, config) and
|
||||||
|
filter(node, state, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
additional predicate fwdFlow(
|
additional predicate fwdFlow(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
|
||||||
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
|
|
||||||
filter(node, state, ap, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlow0(
|
private predicate fwdFlow0(
|
||||||
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
|
||||||
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
|
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
|
||||||
localCc = getLocalCc(mid, cc)
|
localCc = getLocalCc(mid, cc)
|
||||||
|
|
|
|
||||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||||
ap = ap0
|
ap = ap0 and
|
||||||
|
apa = apa0
|
||||||
or
|
or
|
||||||
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
localStep(mid, state0, node, state, false, ap, config, localCc) and
|
||||||
ap0 instanceof ApNil
|
ap0 instanceof ApNil and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid |
|
exists(NodeEx mid |
|
||||||
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and
|
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
|
||||||
jumpStep(mid, node, config) and
|
jumpStep(mid, node, config) and
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
|
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NodeEx mid, FlowState state0, ApNil nil |
|
exists(NodeEx mid, FlowState state0, ApNil nil |
|
||||||
|
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
|
||||||
cc = ccNone() and
|
cc = ccNone() and
|
||||||
summaryCtx = TParameterPositionNone() and
|
summaryCtx = TParameterPositionNone() and
|
||||||
argAp = apNone() and
|
argAp = apNone() and
|
||||||
ap = getApNil(node)
|
ap = getApNil(node) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// store
|
// store
|
||||||
exists(TypedContent tc, Ap ap0 |
|
exists(TypedContent tc, Ap ap0 |
|
||||||
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
|
||||||
ap = apCons(tc, ap0)
|
ap = apCons(tc, ap0) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// read
|
// read
|
||||||
exists(Ap ap0, Content c |
|
exists(Ap ap0, Content c |
|
||||||
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
|
||||||
fwdFlowConsCand(ap0, c, ap, config)
|
fwdFlowConsCand(ap0, c, ap, config) and
|
||||||
|
apa = getApprox(ap)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ApApprox apa |
|
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
|
||||||
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
|
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
||||||
apa = getApprox(ap) and
|
then (
|
||||||
if PrevStage::parameterMayFlowThrough(node, apa, config)
|
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
||||||
then (
|
argAp = apSome(ap)
|
||||||
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
|
) else (
|
||||||
argAp = apSome(ap)
|
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
||||||
) else (
|
|
||||||
summaryCtx = TParameterPositionNone() and argAp = apNone()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
|
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
|
||||||
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
|
||||||
DataFlowCallable inner
|
DataFlowCallable inner
|
||||||
|
|
|
|
||||||
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
|
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
|
||||||
inner = ret.getEnclosingCallable() and
|
inner = ret.getEnclosingCallable() and
|
||||||
cc = getCallContextReturn(inner, call, innercc) and
|
cc = getCallContextReturn(inner, call, innercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
|
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
or
|
or
|
||||||
// flow through a callable
|
// flow through a callable
|
||||||
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
|
||||||
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and
|
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
|
||||||
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType, ApApprox apa1 |
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
|
||||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ApNonNil instanceof Ap {
|
||||||
|
pragma[nomagic]
|
||||||
|
ApNonNil() { not this instanceof ApNil }
|
||||||
|
|
||||||
|
string toString() { result = "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRead0(
|
||||||
|
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ApNonNil ap, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
|
PrevStage::readStepCand(node1, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
getHeadContent(ap) = c
|
getHeadContent(ap) = c
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowIn(
|
private predicate fwdFlowIn(
|
||||||
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
|
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
|
||||||
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
|
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
exists(ArgNodeEx arg, boolean allowsFieldFlow |
|
||||||
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
|
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
|
||||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowRetFromArg(
|
||||||
|
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
|
||||||
|
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCallable c, ReturnKindExt kind |
|
||||||
|
fwdFlow(pragma[only_bind_into](ret), state, ccc,
|
||||||
|
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
|
||||||
|
getApprox(argAp) = argApa and
|
||||||
|
c = ret.getEnclosingCallable() and
|
||||||
|
kind = ret.getKind() and
|
||||||
|
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowInMayFlowThrough(
|
||||||
|
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
|
||||||
|
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
|
||||||
|
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::parameterMayFlowThrough(param, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedup before joining with `flowThroughOutOfCall`
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInMayFlowThroughProj(
|
||||||
|
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `fwdFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowThroughOutOfCall(
|
||||||
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
ApApprox argApa, ApApprox apa, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
|
||||||
|
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowOutFromArg(
|
private predicate fwdFlowOutFromArg(
|
||||||
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
|
||||||
Configuration config
|
ApApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
|
||||||
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
||||||
|
|
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
|
||||||
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
|
|
||||||
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
|
|
||||||
config) and
|
config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
|
||||||
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
ParameterPosition pos, Ap ap, Configuration config
|
ParameterPosition pos, Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx param |
|
exists(ParamNodeEx param |
|
||||||
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
|
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
|
||||||
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
|
|
||||||
pos = param.getPosition()
|
pos = param.getPosition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
|
||||||
fwdFlowConsCand(ap1, c, ap2, config)
|
fwdFlowConsCand(ap1, c, ap2, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate returnFlowsThrough0(
|
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
|
|
||||||
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
|
|
||||||
) {
|
|
||||||
exists(boolean allowsFieldFlow |
|
|
||||||
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
|
|
||||||
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
|
|
||||||
pragma[only_bind_into](config)) and
|
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate returnFlowsThrough(
|
private predicate returnFlowsThrough(
|
||||||
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
|
||||||
Ap ap, Configuration config
|
Ap ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
|
||||||
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
|
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
|
||||||
p.isParameterOf(c, ppos) and
|
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
kind = ret.getKind() and
|
||||||
|
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
|
||||||
|
(if allowsFieldFlow = false then ap instanceof ApNil else any())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughIntoCall(
|
private predicate flowThroughIntoCall(
|
||||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(Ap argAp |
|
exists(ApApprox argApa |
|
||||||
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
|
flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
|
||||||
|
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
|
||||||
|
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
|
|
||||||
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config)) and
|
||||||
|
if allowsFieldFlow = false then argAp instanceof ApNil else any()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowIntoCallAp(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(arg, _, _, _, _, ap, apa, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate flowOutOfCallAp(
|
||||||
|
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ApApprox apa |
|
||||||
|
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
|
||||||
|
fwdFlow(ret, _, _, _, _, ap, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
|
||||||
flowIntoCall(_, node, p, allowsFieldFlow, config) and
|
flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
||||||
returnCtx = TReturnCtxNone()
|
returnCtx = TReturnCtxNone()
|
||||||
)
|
)
|
||||||
|
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
|
||||||
) {
|
) {
|
||||||
exists(NodeEx out, boolean allowsFieldFlow |
|
exists(NodeEx out, boolean allowsFieldFlow |
|
||||||
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
revFlow(out, state, returnCtx, returnAp, ap, config) and
|
||||||
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
|
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
|
||||||
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
if allowsFieldFlow = false then ap instanceof ApNil else any()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
|
||||||
|
* in the flow covered by `revFlow`, where data might flow through the target
|
||||||
|
* callable and back out at `call`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowThroughIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
|
||||||
|
revFlowIsReturned(call, _, _, _, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate revFlowParamToReturn(
|
||||||
|
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
|
parameterFlowThroughAllowed(p, kind)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revFlowInToReturn(
|
private predicate revFlowInToReturn(
|
||||||
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
exists(ParamNodeEx p, boolean allowsFieldFlow |
|
||||||
revFlow(pragma[only_bind_into](p), state,
|
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
|
||||||
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
|
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
|
||||||
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
|
|
||||||
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
|
|
||||||
parameterFlowThroughAllowed(p, kind)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
revFlow(node, _, _, _, ap, config)
|
||||||
|
}
|
||||||
|
|
||||||
// use an alias as a workaround for bad functionality-induced joins
|
// use an alias as a workaround for bad functionality-induced joins
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||||
|
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterFlowsThroughRev(
|
private predicate parameterFlowsThroughRev(
|
||||||
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config
|
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
|
||||||
) {
|
) {
|
||||||
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and
|
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
|
||||||
parameterFlowThroughAllowed(p, kind)
|
parameterFlowThroughAllowed(p, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, ReturnKindExt kind |
|
exists(RetNodeEx ret, ReturnKindExt kind |
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
parameterFlowsThroughRev(p, ap, kind, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
|
predicate returnMayFlowThrough(
|
||||||
exists(ParamNodeEx p, Ap ap |
|
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
|
||||||
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
|
) {
|
||||||
parameterFlowsThroughRev(p, ap, kind, config)
|
exists(ParamNodeEx p |
|
||||||
|
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
|
||||||
|
parameterFlowsThroughRev(p, argAp, kind, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate revFlowInToReturnIsReturned(
|
||||||
|
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
|
||||||
|
Ap ap, Configuration config
|
||||||
|
) {
|
||||||
|
exists(ReturnKindExt returnKind0, Ap returnAp0 |
|
||||||
|
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
||||||
|
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
|
||||||
exists(
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
|
||||||
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
|
|
||||||
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
|
||||||
|
|
|
||||||
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and
|
||||||
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
|
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
|
||||||
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate localFlowBigStep(
|
predicate localFlowBigStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
|
DataFlowType t, Configuration config, LocalCallContext callContext
|
||||||
) {
|
) {
|
||||||
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
|
localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
|
||||||
localFlowExit(node2, state1, config) and
|
localFlowExit(node2, state1, config) and
|
||||||
state1 = state2
|
state1 = state2
|
||||||
or
|
or
|
||||||
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
|
||||||
state1 != state2 and
|
state1 != state2 and
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
apf = TFrontNil(node2.getDataFlowType()) and
|
t = node2.getDataFlowType() and
|
||||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||||
isUnreachableInCallCached(node1.asNode(), call) or
|
isUnreachableInCallCached(node1.asNode(), call) or
|
||||||
|
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
|
||||||
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
private module PrevStage = Stage2;
|
private module PrevStage = Stage2;
|
||||||
|
|
||||||
|
class Ap = ApproxAccessPathFront;
|
||||||
|
|
||||||
|
class ApNil = ApproxAccessPathFrontNil;
|
||||||
|
|
||||||
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||||
|
|
||||||
|
ApNil getApNil(NodeEx node) {
|
||||||
|
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[tc, tail]
|
||||||
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
pragma[noinline]
|
||||||
|
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
||||||
|
|
||||||
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
|
ApOption apNone() { result = TApproxAccessPathFrontNone() }
|
||||||
|
|
||||||
|
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
|
||||||
|
|
||||||
|
import BooleanCallContext
|
||||||
|
|
||||||
|
predicate localStep(
|
||||||
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
|
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
|
||||||
|
) {
|
||||||
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
exists(lcc)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
||||||
|
|
||||||
|
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
|
||||||
|
exists(Content c |
|
||||||
|
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
|
||||||
|
expectsContentEx(node, c) and
|
||||||
|
c = ap.getAHead().getContent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
|
||||||
|
|
||||||
|
bindingset[node, state, ap, config]
|
||||||
|
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||||
|
exists(state) and
|
||||||
|
exists(config) and
|
||||||
|
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
|
||||||
|
(
|
||||||
|
notExpectsContent(node)
|
||||||
|
or
|
||||||
|
expectsContentCand(node, ap, config)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[ap, contentType]
|
||||||
|
predicate typecheckStore(Ap ap, DataFlowType contentType) {
|
||||||
|
// We need to typecheck stores here, since reverse flow through a getter
|
||||||
|
// might have a different type here compared to inside the getter.
|
||||||
|
compatibleTypes(ap.getType(), contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage3 implements StageSig {
|
||||||
|
import MkStage<Stage2>::Stage<Stage3Param>
|
||||||
|
}
|
||||||
|
|
||||||
|
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
|
private module PrevStage = Stage3;
|
||||||
|
|
||||||
class Ap = AccessPathFront;
|
class Ap = AccessPathFront;
|
||||||
|
|
||||||
class ApNil = AccessPathFrontNil;
|
class ApNil = AccessPathFrontNil;
|
||||||
|
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
|
||||||
|
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
|
|
||||||
import BooleanCallContext
|
import BooleanCallContext
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate localStep(
|
predicate localStep(
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
|
||||||
|
exists(lcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
|
pragma[nomagic]
|
||||||
|
predicate flowOutOfCall(
|
||||||
|
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate flowIntoCall = flowIntoCallNodeCand2/5;
|
pragma[nomagic]
|
||||||
|
predicate flowIntoCall(
|
||||||
|
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
|
||||||
|
Configuration config
|
||||||
|
) {
|
||||||
|
exists(FlowState state |
|
||||||
|
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||||
|
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
|
||||||
|
pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
|
||||||
|
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage3 implements StageSig {
|
private module Stage4 implements StageSig {
|
||||||
import MkStage<Stage2>::Stage<Stage3Param>
|
import MkStage<Stage3>::Stage<Stage4Param>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
|
||||||
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathFront apf |
|
exists(AccessPathFront apf |
|
||||||
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
|
||||||
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
|
||||||
*/
|
*/
|
||||||
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
|
||||||
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
exists(int tails, int nodes, int apLimit, int tupleLimit |
|
||||||
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and
|
tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
|
||||||
nodes =
|
nodes =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
or
|
or
|
||||||
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
|
||||||
) and
|
) and
|
||||||
|
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
||||||
private newtype TAccessPathApprox =
|
private newtype TAccessPathApprox =
|
||||||
TNil(DataFlowType t) or
|
TNil(DataFlowType t) or
|
||||||
TConsNil(TypedContent tc, DataFlowType t) {
|
TConsNil(TypedContent tc, DataFlowType t) {
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
not expensiveLen2unfolding(tc, _)
|
not expensiveLen2unfolding(tc, _)
|
||||||
} or
|
} or
|
||||||
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
|
||||||
Stage3::consCand(tc1, TFrontHead(tc2), _) and
|
Stage4::consCand(tc1, TFrontHead(tc2), _) and
|
||||||
len in [2 .. accessPathLimit()] and
|
len in [2 .. accessPathLimit()] and
|
||||||
not expensiveLen2unfolding(tc1, _)
|
not expensiveLen2unfolding(tc1, _)
|
||||||
} or
|
} or
|
||||||
|
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
override AccessPathApprox pop(TypedContent head) {
|
override AccessPathApprox pop(TypedContent head) {
|
||||||
head = tc and
|
head = tc and
|
||||||
(
|
(
|
||||||
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
|
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
|
||||||
result = TConsCons(tc2, _, len - 1)
|
result = TConsCons(tc2, _, len - 1)
|
||||||
or
|
or
|
||||||
len = 2 and
|
len = 2 and
|
||||||
|
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
|
||||||
or
|
or
|
||||||
exists(DataFlowType t |
|
exists(DataFlowType t |
|
||||||
len = 1 and
|
len = 1 and
|
||||||
Stage3::consCand(tc, TFrontNil(t), _) and
|
Stage4::consCand(tc, TFrontNil(t), _) and
|
||||||
result = TNil(t)
|
result = TNil(t)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
private module Stage5Param implements MkStage<Stage4>::StageParam {
|
||||||
private module PrevStage = Stage3;
|
private module PrevStage = Stage4;
|
||||||
|
|
||||||
class Ap = AccessPathApprox;
|
class Ap = AccessPathApprox;
|
||||||
|
|
||||||
class ApNil = AccessPathApproxNil;
|
class ApNil = AccessPathApproxNil;
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
|
||||||
|
|
||||||
ApNil getApNil(NodeEx node) {
|
ApNil getApNil(NodeEx node) {
|
||||||
|
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||||
ApNil ap, Configuration config, LocalCc lcc
|
ApNil ap, Configuration config, LocalCc lcc
|
||||||
) {
|
) {
|
||||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc)
|
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
|
||||||
|
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
|
||||||
|
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
|
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||||
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
|
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
|
||||||
|
|
||||||
bindingset[conf, result]
|
bindingset[conf, result]
|
||||||
private Configuration unbindConf(Configuration conf) {
|
private Configuration unbindConf(Configuration conf) {
|
||||||
|
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa0 |
|
exists(AccessPathApprox apa0 |
|
||||||
c = n.getEnclosingCallable() and
|
c = n.getEnclosingCallable() and
|
||||||
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
|
||||||
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
|
||||||
TAccessPathApproxSome(apa), apa0, config)
|
TAccessPathApproxSome(apa), apa0, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
|
||||||
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
|
||||||
Stage4::parameterMayFlowThrough(p, apa, config) and
|
Stage5::parameterMayFlowThrough(p, apa, config) and
|
||||||
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
nodeMayUseSummary0(n, c, pos, state, apa, config) and
|
||||||
p.isParameterOf(c, pos)
|
p.isParameterOf(c, pos)
|
||||||
)
|
)
|
||||||
|
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
|
||||||
TSummaryCtxNone() or
|
TSummaryCtxNone() or
|
||||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
|
||||||
exists(Configuration config |
|
exists(Configuration config |
|
||||||
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
|
||||||
Stage4::revFlow(p, state, _, config)
|
Stage5::revFlow(p, state, _, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
len = apa.len() and
|
len = apa.len() and
|
||||||
result =
|
result =
|
||||||
strictcount(AccessPathFront apf |
|
strictcount(AccessPathFront apf |
|
||||||
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
|
||||||
config)
|
config)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
|
||||||
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
|
||||||
result =
|
result =
|
||||||
strictcount(NodeEx n, FlowState state |
|
strictcount(NodeEx n, FlowState state |
|
||||||
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
|
||||||
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
||||||
exists(TypedContent head |
|
exists(TypedContent head |
|
||||||
apa.pop(head) = result and
|
apa.pop(head) = result and
|
||||||
Stage4::consCand(head, result, config)
|
Stage5::consCand(head, result, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2768,7 +3011,7 @@ private newtype TPathNode =
|
||||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
// A PathNode is introduced by a source ...
|
// A PathNode is introduced by a source ...
|
||||||
Stage4::revFlow(node, state, config) and
|
Stage5::revFlow(node, state, config) and
|
||||||
sourceNode(node, state, config) and
|
sourceNode(node, state, config) and
|
||||||
(
|
(
|
||||||
if hasSourceCallCtx(config)
|
if hasSourceCallCtx(config)
|
||||||
|
@ -2782,7 +3025,7 @@ private newtype TPathNode =
|
||||||
exists(PathNodeMid mid |
|
exists(PathNodeMid mid |
|
||||||
pathStep(mid, node, state, cc, sc, ap) and
|
pathStep(mid, node, state, cc, sc, ap) and
|
||||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||||
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
|
||||||
|
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
|
||||||
override TypedContent getHead() { result = head1 }
|
override TypedContent getHead() { result = head1 }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head1, result.getApprox(), _) and
|
Stage5::consCand(head1, result.getApprox(), _) and
|
||||||
result.getHead() = head2 and
|
result.getHead() = head2 and
|
||||||
result.length() = len - 1
|
result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||||
override TypedContent getHead() { result = head }
|
override TypedContent getHead() { result = head }
|
||||||
|
|
||||||
override AccessPath getTail() {
|
override AccessPath getTail() {
|
||||||
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||||
|
@ -3347,7 +3590,8 @@ private predicate pathStep(
|
||||||
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
||||||
|
|
|
|
||||||
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
|
||||||
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and
|
localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
|
||||||
|
localCC) and
|
||||||
ap0 instanceof AccessPathNil
|
ap0 instanceof AccessPathNil
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
tc = ap0.getHead() and
|
tc = ap0.getHead() and
|
||||||
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
|
||||||
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
|
||||||
) {
|
) {
|
||||||
ap0 = mid.getAp() and
|
ap0 = mid.getAp() and
|
||||||
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
|
||||||
state = mid.getState() and
|
state = mid.getState() and
|
||||||
cc = mid.getCallContext()
|
cc = mid.getCallContext()
|
||||||
}
|
}
|
||||||
|
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
|
||||||
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
result.asNode() = kind.getAnOutNode(call) and
|
result.asNode() = kind.getAnOutNode(call) and
|
||||||
Stage4::revFlow(result, _, apa, config)
|
Stage5::revFlow(result, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3472,7 +3716,7 @@ private predicate parameterCand(
|
||||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, apa, config) and
|
Stage5::revFlow(p, _, apa, config) and
|
||||||
p.isParameterOf(callable, pos)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3751,9 +3995,17 @@ predicate stageStats(
|
||||||
n = 45 and
|
n = 45 and
|
||||||
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples)
|
stage = "5 Fwd" and
|
||||||
|
n = 50 and
|
||||||
|
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
|
||||||
or
|
or
|
||||||
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples)
|
stage = "5 Rev" and
|
||||||
|
n = 55 and
|
||||||
|
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
|
||||||
|
or
|
||||||
|
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
|
||||||
|
or
|
||||||
|
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module FlowExploration {
|
private module FlowExploration {
|
||||||
|
|
|
@ -904,6 +904,13 @@ private module Cached {
|
||||||
TElementContent() or
|
TElementContent() or
|
||||||
TSyntheticFieldContent(SyntheticField f)
|
TSyntheticFieldContent(SyntheticField f)
|
||||||
|
|
||||||
|
cached
|
||||||
|
newtype TContentApprox =
|
||||||
|
TFieldApproxContent(string firstChar) { firstChar = approximateFieldContent(_) } or
|
||||||
|
TPropertyApproxContent(string firstChar) { firstChar = approximatePropertyContent(_) } or
|
||||||
|
TElementApproxContent() or
|
||||||
|
TSyntheticFieldApproxContent()
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
|
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
|
||||||
not t1 instanceof Gvn::TypeParameterGvnType and
|
not t1 instanceof Gvn::TypeParameterGvnType and
|
||||||
|
@ -2246,6 +2253,46 @@ predicate allowParameterReturnInSelf(ParameterNode p) {
|
||||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
|
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An approximated `Content`. */
|
||||||
|
class ContentApprox extends TContentApprox {
|
||||||
|
/** Gets a textual representation of this approximated `Content`. */
|
||||||
|
string toString() {
|
||||||
|
exists(string firstChar |
|
||||||
|
this = TFieldApproxContent(firstChar) and result = "approximated field " + firstChar
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(string firstChar |
|
||||||
|
this = TPropertyApproxContent(firstChar) and result = "approximated property " + firstChar
|
||||||
|
)
|
||||||
|
or
|
||||||
|
this = TElementApproxContent() and result = "element"
|
||||||
|
or
|
||||||
|
this = TSyntheticFieldApproxContent() and result = "approximated synthetic field"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a string for approximating the name of a field. */
|
||||||
|
private string approximateFieldContent(FieldContent fc) {
|
||||||
|
result = fc.getField().getName().prefix(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a string for approximating the name of a property. */
|
||||||
|
private string approximatePropertyContent(PropertyContent pc) {
|
||||||
|
result = pc.getProperty().getName().prefix(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets an approximated value for content `c`. */
|
||||||
|
pragma[nomagic]
|
||||||
|
ContentApprox getContentApprox(Content c) {
|
||||||
|
result = TFieldApproxContent(approximateFieldContent(c))
|
||||||
|
or
|
||||||
|
result = TPropertyApproxContent(approximatePropertyContent(c))
|
||||||
|
or
|
||||||
|
c instanceof ElementContent and result = TElementApproxContent()
|
||||||
|
or
|
||||||
|
c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A module importing the modules that provide synthetic field declarations,
|
* A module importing the modules that provide synthetic field declarations,
|
||||||
* ensuring that they are visible to the taint tracking / data flow library.
|
* ensuring that they are visible to the taint tracking / data flow library.
|
||||||
|
|
|
@ -257,9 +257,7 @@ class SystemNullReferenceExceptionClass extends SystemClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The `System.Object` class. */
|
/** The `System.Object` class. */
|
||||||
class SystemObjectClass extends SystemClass {
|
class SystemObjectClass extends SystemClass instanceof ObjectType {
|
||||||
SystemObjectClass() { this instanceof ObjectType }
|
|
||||||
|
|
||||||
/** Gets the `Equals(object)` method. */
|
/** Gets the `Equals(object)` method. */
|
||||||
Method getEqualsMethod() {
|
Method getEqualsMethod() {
|
||||||
result.getDeclaringType() = this and
|
result.getDeclaringType() = this and
|
||||||
|
|
|
@ -56,6 +56,4 @@ class ProtectSanitizer extends Sanitizer {
|
||||||
/**
|
/**
|
||||||
* An external location sink.
|
* An external location sink.
|
||||||
*/
|
*/
|
||||||
class ExternalSink extends Sink {
|
class ExternalSink extends Sink instanceof ExternalLocationSink { }
|
||||||
ExternalSink() { this instanceof ExternalLocationSink }
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,14 +38,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A source of local user input. */
|
/** A source of local user input. */
|
||||||
class LocalSource extends Source {
|
class LocalSource extends Source instanceof LocalFlowSource { }
|
||||||
LocalSource() { this instanceof LocalFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sink in `System.Diagnostic.Process` or its related classes.
|
* A sink in `System.Diagnostic.Process` or its related classes.
|
||||||
|
|
|
@ -43,9 +43,7 @@ class Configuration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The result of a reverse dns may be user-controlled. */
|
/** The result of a reverse dns may be user-controlled. */
|
||||||
class ReverseDnsSource extends Source {
|
class ReverseDnsSource extends Source {
|
||||||
|
|
|
@ -39,6 +39,4 @@ private class PrivateDataSource extends Source {
|
||||||
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
|
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExternalLocation extends Sink {
|
private class ExternalLocation extends Sink instanceof ExternalLocationSink { }
|
||||||
ExternalLocation() { this instanceof ExternalLocationSink }
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,8 +17,7 @@ abstract class SafeExternalApiCallable extends Callable { }
|
||||||
/** DEPRECATED: Alias for SafeExternalApiCallable */
|
/** DEPRECATED: Alias for SafeExternalApiCallable */
|
||||||
deprecated class SafeExternalAPICallable = SafeExternalApiCallable;
|
deprecated class SafeExternalAPICallable = SafeExternalApiCallable;
|
||||||
|
|
||||||
private class SummarizedCallableSafe extends SafeExternalApiCallable {
|
private class SummarizedCallableSafe extends SafeExternalApiCallable instanceof SummarizedCallable {
|
||||||
SummarizedCallableSafe() { this instanceof SummarizedCallable }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The default set of "safe" external APIs. */
|
/** The default set of "safe" external APIs. */
|
||||||
|
|
|
@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP
|
* An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP
|
||||||
|
|
|
@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
private class RemoteSource extends Source {
|
private class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class HtmlSanitizer extends Sanitizer {
|
private class HtmlSanitizer extends Sanitizer {
|
||||||
HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }
|
HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }
|
||||||
|
|
|
@ -43,9 +43,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The input argument to a call to `XmlReader.Create` where the input will not be validated against
|
* The input argument to a call to `XmlReader.Create` where the input will not be validated against
|
||||||
|
|
|
@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression that represents a regular expression with potential exponential behavior.
|
* An expression that represents a regular expression with potential exponential behavior.
|
||||||
|
|
|
@ -37,9 +37,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `pattern` argument to a construction of a `Regex`.
|
* A `pattern` argument to a construction of a `Regex`.
|
||||||
|
|
|
@ -37,14 +37,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A source of local user input. */
|
/** A source of local user input. */
|
||||||
class LocalSource extends Source {
|
class LocalSource extends Source instanceof LocalFlowSource { }
|
||||||
LocalSource() { this instanceof LocalFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** An argument to the `ConnectionString` property on a data connection class. */
|
/** An argument to the `ConnectionString` property on a data connection class. */
|
||||||
class SqlConnectionStringSink extends Sink {
|
class SqlConnectionStringSink extends Sink {
|
||||||
|
|
|
@ -38,14 +38,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A source of local user input. */
|
/** A source of local user input. */
|
||||||
class LocalSource extends Source {
|
class LocalSource extends Source instanceof LocalFlowSource { }
|
||||||
LocalSource() { this instanceof LocalFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** An SQL expression passed to an API call that executes SQL. */
|
/** An SQL expression passed to an API call that executes SQL. */
|
||||||
class SqlInjectionExprSink extends Sink {
|
class SqlInjectionExprSink extends Sink {
|
||||||
|
|
|
@ -39,9 +39,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A path argument to a `File` method call.
|
* A path argument to a `File` method call.
|
||||||
|
|
|
@ -44,9 +44,7 @@ abstract private class ConstructorOrStaticMethodSink extends Sink { }
|
||||||
*/
|
*/
|
||||||
abstract class Sanitizer extends DataFlow::Node { }
|
abstract class Sanitizer extends DataFlow::Node { }
|
||||||
|
|
||||||
private class RemoteSource extends Source {
|
private class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User input to object method call deserialization flow tracking.
|
* User input to object method call deserialization flow tracking.
|
||||||
|
|
|
@ -50,9 +50,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
|
* A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a
|
||||||
|
|
|
@ -14,9 +14,7 @@ private import semmle.code.csharp.security.Sanitizers
|
||||||
*/
|
*/
|
||||||
abstract class Source extends DataFlow::Node { }
|
abstract class Source extends DataFlow::Node { }
|
||||||
|
|
||||||
private class RemoteSource extends Source {
|
private class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data flow sink for untrusted user input used in XML processing.
|
* A data flow sink for untrusted user input used in XML processing.
|
||||||
|
|
|
@ -37,9 +37,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
|
/** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
|
||||||
class XPathExpressionCompileSink extends Sink {
|
class XPathExpressionCompileSink extends Sink {
|
||||||
|
|
|
@ -149,9 +149,7 @@ class TaintTrackingConfiguration extends TaintTracking2::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
private class RemoteSource extends Source {
|
private class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ private class ExternalXssSink extends Sink {
|
||||||
ExternalXssSink() { sinkNode(this, "xss") }
|
ExternalXssSink() { sinkNode(this, "xss") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HtmlSinkSink extends Sink {
|
private class HtmlSinkSink extends Sink instanceof HtmlSink {
|
||||||
HtmlSinkSink() { this instanceof HtmlSink }
|
|
||||||
|
|
||||||
override string explanation() {
|
override string explanation() {
|
||||||
this instanceof WebPageWriteLiteralSink and
|
this instanceof WebPageWriteLiteralSink and
|
||||||
result = "System.Web.WebPages.WebPage.WriteLiteral() method"
|
result = "System.Web.WebPages.WebPage.WriteLiteral() method"
|
||||||
|
|
|
@ -12,6 +12,7 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls
|
||||||
private import semmle.code.csharp.frameworks.WCF
|
private import semmle.code.csharp.frameworks.WCF
|
||||||
private import semmle.code.csharp.frameworks.microsoft.Owin
|
private import semmle.code.csharp.frameworks.microsoft.Owin
|
||||||
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||||
|
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||||
|
|
||||||
/** A data flow source of remote user input. */
|
/** A data flow source of remote user input. */
|
||||||
abstract class RemoteFlowSource extends DataFlow::Node {
|
abstract class RemoteFlowSource extends DataFlow::Node {
|
||||||
|
@ -261,3 +262,9 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl
|
||||||
|
|
||||||
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
|
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ExternalRemoteFlowSource extends RemoteFlowSource {
|
||||||
|
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
|
||||||
|
|
||||||
|
override string getSourceType() { result = "external" }
|
||||||
|
}
|
||||||
|
|
|
@ -44,9 +44,7 @@ class SuppressionComment extends CommentLine {
|
||||||
/**
|
/**
|
||||||
* The scope of an alert suppression comment.
|
* The scope of an alert suppression comment.
|
||||||
*/
|
*/
|
||||||
class SuppressionScope extends @commentline {
|
class SuppressionScope extends @commentline instanceof SuppressionComment {
|
||||||
SuppressionScope() { this instanceof SuppressionComment }
|
|
||||||
|
|
||||||
/** Gets a suppression comment with this scope. */
|
/** Gets a suppression comment with this scope. */
|
||||||
SuppressionComment getSuppressionComment() { result = this }
|
SuppressionComment getSuppressionComment() { result = this }
|
||||||
|
|
||||||
|
@ -60,7 +58,7 @@ class SuppressionScope extends @commentline {
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
) {
|
) {
|
||||||
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
super.covers(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
|
|
|
@ -24,6 +24,12 @@ class TestLibrary extends RefType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if the given callable is not worth supporting. */
|
||||||
|
private predicate isUninteresting(DotNet::Callable c) {
|
||||||
|
c.getDeclaringType() instanceof TestLibrary or
|
||||||
|
c.(Constructor).isParameterless()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An external API from either the C# Standard Library or a 3rd party library.
|
* An external API from either the C# Standard Library or a 3rd party library.
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +37,8 @@ class ExternalApi extends DotNet::Callable {
|
||||||
ExternalApi() {
|
ExternalApi() {
|
||||||
this.isUnboundDeclaration() and
|
this.isUnboundDeclaration() and
|
||||||
this.fromLibrary() and
|
this.fromLibrary() and
|
||||||
this.(Modifiable).isEffectivelyPublic()
|
this.(Modifiable).isEffectivelyPublic() and
|
||||||
|
not isUninteresting(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,17 +91,6 @@ class ExternalApi extends DotNet::Callable {
|
||||||
defaultAdditionalTaintStep(this.getAnInput(), _)
|
defaultAdditionalTaintStep(this.getAnInput(), _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this API is a constructor without parameters. */
|
|
||||||
private predicate isParameterlessConstructor() {
|
|
||||||
this instanceof Constructor and this.getNumberOfParameters() = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API is part of a common testing library or framework. */
|
|
||||||
private predicate isTestLibrary() { this.getDeclaringType() instanceof TestLibrary }
|
|
||||||
|
|
||||||
/** Holds if this API is not worth supporting. */
|
|
||||||
predicate isUninteresting() { this.isTestLibrary() or this.isParameterlessConstructor() }
|
|
||||||
|
|
||||||
/** Holds if this API is a known source. */
|
/** Holds if this API is a known source. */
|
||||||
predicate isSource() {
|
predicate isSource() {
|
||||||
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
||||||
|
|
|
@ -14,8 +14,7 @@ private predicate getRelevantUsages(string namespace, int usages) {
|
||||||
usages =
|
usages =
|
||||||
strictcount(Call c, ExternalApi api |
|
strictcount(Call c, ExternalApi api |
|
||||||
c.getTarget().getUnboundDeclaration() = api and
|
c.getTarget().getUnboundDeclaration() = api and
|
||||||
api.getNamespace() = namespace and
|
api.getNamespace() = namespace
|
||||||
not api.isUninteresting()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,8 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
|
||||||
private import ExternalApi
|
private import ExternalApi
|
||||||
|
|
||||||
private predicate relevant(ExternalApi api) {
|
private predicate relevant(ExternalApi api) {
|
||||||
not api.isUninteresting() and
|
api.isSupported() or
|
||||||
(
|
api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||||
api.isSupported() or
|
|
||||||
api instanceof FlowSummaryImpl::Public::NeutralCallable
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from string info, int usages
|
from string info, int usages
|
||||||
|
|
|
@ -10,10 +10,7 @@ private import csharp
|
||||||
private import semmle.code.csharp.dispatch.Dispatch
|
private import semmle.code.csharp.dispatch.Dispatch
|
||||||
private import ExternalApi
|
private import ExternalApi
|
||||||
|
|
||||||
private predicate relevant(ExternalApi api) {
|
private predicate relevant(ExternalApi api) { api.isSink() }
|
||||||
not api.isUninteresting() and
|
|
||||||
api.isSink()
|
|
||||||
}
|
|
||||||
|
|
||||||
from string info, int usages
|
from string info, int usages
|
||||||
where Results<relevant/1>::restrict(info, usages)
|
where Results<relevant/1>::restrict(info, usages)
|
||||||
|
|
|
@ -10,10 +10,7 @@ private import csharp
|
||||||
private import semmle.code.csharp.dispatch.Dispatch
|
private import semmle.code.csharp.dispatch.Dispatch
|
||||||
private import ExternalApi
|
private import ExternalApi
|
||||||
|
|
||||||
private predicate relevant(ExternalApi api) {
|
private predicate relevant(ExternalApi api) { api.isSource() }
|
||||||
not api.isUninteresting() and
|
|
||||||
api.isSource()
|
|
||||||
}
|
|
||||||
|
|
||||||
from string info, int usages
|
from string info, int usages
|
||||||
where Results<relevant/1>::restrict(info, usages)
|
where Results<relevant/1>::restrict(info, usages)
|
||||||
|
|
|
@ -10,10 +10,7 @@ private import csharp
|
||||||
private import semmle.code.csharp.dispatch.Dispatch
|
private import semmle.code.csharp.dispatch.Dispatch
|
||||||
private import ExternalApi
|
private import ExternalApi
|
||||||
|
|
||||||
private predicate relevant(ExternalApi api) {
|
private predicate relevant(ExternalApi api) { api.hasSummary() }
|
||||||
not api.isUninteresting() and
|
|
||||||
api.hasSummary()
|
|
||||||
}
|
|
||||||
|
|
||||||
from string info, int usages
|
from string info, int usages
|
||||||
where Results<relevant/1>::restrict(info, usages)
|
where Results<relevant/1>::restrict(info, usages)
|
||||||
|
|
|
@ -12,7 +12,6 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
|
||||||
private import ExternalApi
|
private import ExternalApi
|
||||||
|
|
||||||
private predicate relevant(ExternalApi api) {
|
private predicate relevant(ExternalApi api) {
|
||||||
not api.isUninteresting() and
|
|
||||||
not api.isSupported() and
|
not api.isSupported() and
|
||||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A source of remote user input. */
|
/** A source of remote user input. */
|
||||||
class RemoteSource extends Source {
|
class RemoteSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A path argument to a `WebClient` method call that has an address argument.
|
* A path argument to a `WebClient` method call that has an address argument.
|
||||||
|
|
|
@ -58,9 +58,7 @@ module RequestForgery {
|
||||||
* A remote data flow source taken as a source
|
* A remote data flow source taken as a source
|
||||||
* for Server Side Request Forgery(SSRF) Vulnerabilities.
|
* for Server Side Request Forgery(SSRF) Vulnerabilities.
|
||||||
*/
|
*/
|
||||||
private class RemoteFlowSourceAsSource extends Source {
|
private class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { }
|
||||||
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An url argument to a `HttpRequestMessage` constructor call
|
* An url argument to a `HttpRequestMessage` constructor call
|
||||||
|
|
|
@ -16,7 +16,6 @@ private import Telemetry.ExternalApi
|
||||||
from Call c, ExternalApi api
|
from Call c, ExternalApi api
|
||||||
where
|
where
|
||||||
c.getTarget().getUnboundDeclaration() = api and
|
c.getTarget().getUnboundDeclaration() = api and
|
||||||
not api.isUninteresting() and
|
|
||||||
not api.isSupported() and
|
not api.isSupported() and
|
||||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||||
select c, "Call to unsupported external API $@.", api, api.toString()
|
select c, "Call to unsupported external API $@.", api, api.toString()
|
||||||
|
|
|
@ -38,7 +38,9 @@ private predicate isRelevantForModels(CS::Callable api) {
|
||||||
api.getDeclaringType().getNamespace().getFullName() != "" and
|
api.getDeclaringType().getNamespace().getFullName() != "" and
|
||||||
not api instanceof CS::ConversionOperator and
|
not api instanceof CS::ConversionOperator and
|
||||||
not api instanceof Util::MainMethod and
|
not api instanceof Util::MainMethod and
|
||||||
not api instanceof CS::Destructor
|
not api instanceof CS::Destructor and
|
||||||
|
not api instanceof CS::AnonymousFunctionExpr and
|
||||||
|
not api.(CS::Constructor).isParameterless()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
import csharp
|
import csharp
|
||||||
import Common
|
import Common
|
||||||
|
|
||||||
class TTConfig extends TaintTracking::Configuration {
|
class TTConfig extends TaintTracking::Configuration instanceof Config {
|
||||||
Config c;
|
override predicate isSource(DataFlow::Node source) { Config.super.isSource(source) }
|
||||||
|
|
||||||
TTConfig() { this = c }
|
override predicate isSink(DataFlow::Node sink) { Config.super.isSink(sink) }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { c.isSource(source) }
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { c.isSink(sink) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from TTConfig c, DataFlow::Node source, DataFlow::Node sink
|
from TTConfig c, DataFlow::Node source, DataFlow::Node sink
|
||||||
|
|
|
@ -6,14 +6,10 @@ import csharp
|
||||||
import Common
|
import Common
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
class TTConfig extends TaintTracking::Configuration {
|
class TTConfig extends TaintTracking::Configuration instanceof Config {
|
||||||
Config c;
|
override predicate isSource(DataFlow::Node source) { Config.super.isSource(source) }
|
||||||
|
|
||||||
TTConfig() { this = c }
|
override predicate isSink(DataFlow::Node sink) { Config.super.isSink(sink) }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { c.isSource(source) }
|
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { c.isSink(sink) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from TTConfig c, DataFlow::PathNode source, DataFlow::PathNode sink, string s
|
from TTConfig c, DataFlow::PathNode source, DataFlow::PathNode sink, string s
|
||||||
|
|
|
@ -6,9 +6,7 @@ private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
|
||||||
IncludeAllSummarizedCallable() { exists(this) }
|
IncludeAllSummarizedCallable() { exists(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IncludeNeutralCallable extends RelevantNeutralCallable {
|
private class IncludeNeutralCallable extends RelevantNeutralCallable instanceof FlowSummaryImpl::Public::NeutralCallable {
|
||||||
IncludeNeutralCallable() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
|
|
||||||
|
|
||||||
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
|
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
|
||||||
final override string getCallableCsv() { result = Csv::asPartialNeutralModel(this) }
|
final override string getCallableCsv() { result = Csv::asPartialNeutralModel(this) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ import shared.FlowSummaries
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
|
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
|
||||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||||
|
|
||||||
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
|
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable instanceof SummarizedCallable {
|
||||||
IncludeFilteredSummarizedCallable() { this instanceof SummarizedCallable }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if flow is propagated between `input` and `output` and
|
* Holds if flow is propagated between `input` and `output` and
|
||||||
* if there is no summary for a callable in a `base` class or interface
|
* if there is no summary for a callable in a `base` class or interface
|
||||||
|
@ -13,7 +11,7 @@ class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
|
||||||
override predicate relevantSummary(
|
override predicate relevantSummary(
|
||||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||||
) {
|
) {
|
||||||
this.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and
|
super.propagatesFlow(input, output, preservesValue) and
|
||||||
not exists(IncludeSummarizedCallable rsc |
|
not exists(IncludeSummarizedCallable rsc |
|
||||||
isBaseCallableOrPrototype(rsc) and
|
isBaseCallableOrPrototype(rsc) and
|
||||||
rsc.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and
|
rsc.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and
|
||||||
|
|
|
@ -2,8 +2,7 @@ import semmle.code.csharp.frameworks.EntityFramework::EntityFramework
|
||||||
import shared.FlowSummaries
|
import shared.FlowSummaries
|
||||||
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
||||||
|
|
||||||
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable {
|
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable instanceof EFSummarizedCallable {
|
||||||
IncludeEFSummarizedCallable() { this instanceof EFSummarizedCallable }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query predicate sourceNode(DataFlow::Node node, string kind) {
|
query predicate sourceNode(DataFlow::Node node, string kind) {
|
||||||
|
|
|
@ -131,4 +131,15 @@ public class CollectionFlow
|
||||||
{
|
{
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A neutral model should not be created for a parameterless constructor.
|
||||||
|
public class ParameterlessConstructor
|
||||||
|
{
|
||||||
|
public bool IsInitialized;
|
||||||
|
|
||||||
|
public ParameterlessConstructor()
|
||||||
|
{
|
||||||
|
IsInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,4 +5,4 @@ where
|
||||||
a.getAnOperand() = v.getAnAccess() and
|
a.getAnOperand() = v.getAnAccess() and
|
||||||
cmp.getAnOperand() = a and
|
cmp.getAnOperand() = a and
|
||||||
cmp.getAnOperand() = v.getAnAccess()
|
cmp.getAnOperand() = v.getAnAccess()
|
||||||
select cmp, "Overflow check."
|
select cmp, "Overflow check."
|
||||||
|
|
|
@ -6,4 +6,4 @@ where
|
||||||
cmp.getAnOperand() = a and
|
cmp.getAnOperand() = a and
|
||||||
cmp.getAnOperand() = v.getAnAccess() and
|
cmp.getAnOperand() = v.getAnAccess() and
|
||||||
forall(Expr op | op = a.getAnOperand() | isSmall(op))
|
forall(Expr op | op = a.getAnOperand() | isSmall(op))
|
||||||
select cmp, "Bad overflow check."
|
select cmp, "Bad overflow check."
|
||||||
|
|
|
@ -9,4 +9,4 @@ where
|
||||||
cmp.getAnOperand() = v.getAnAccess() and
|
cmp.getAnOperand() = v.getAnAccess() and
|
||||||
forall(Expr op | op = a.getAnOperand() | isSmall(op)) and
|
forall(Expr op | op = a.getAnOperand() | isSmall(op)) and
|
||||||
not isSmall(a.getExplicitlyConverted())
|
not isSmall(a.getExplicitlyConverted())
|
||||||
select cmp, "Bad overflow check"
|
select cmp, "Bad overflow check"
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
from FunctionCall alloc, FunctionCall free, LocalScopeVariable v
|
from FunctionCall alloc, FunctionCall free, LocalScopeVariable v
|
||||||
where allocationCall(alloc)
|
where
|
||||||
and alloc = v.getAnAssignedValue()
|
allocationCall(alloc) and
|
||||||
and freeCall(free, v.getAnAccess())
|
alloc = v.getAnAssignedValue() and
|
||||||
and alloc.getASuccessor+() = free
|
freeCall(free, v.getAnAccess()) and
|
||||||
|
alloc.getASuccessor+() = free
|
||||||
select alloc, free
|
select alloc, free
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
from FunctionCall free, LocalScopeVariable v, VariableAccess u
|
from FunctionCall free, LocalScopeVariable v, VariableAccess u
|
||||||
where freeCall(free, v.getAnAccess())
|
where
|
||||||
and u = v.getAnAccess()
|
freeCall(free, v.getAnAccess()) and
|
||||||
and u.isRValue()
|
u = v.getAnAccess() and
|
||||||
and free.getASuccessor+() = u
|
u.isRValue() and
|
||||||
select free, u
|
free.getASuccessor+() = u
|
||||||
|
select free, u
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче