Merge branch 'main' into redsun82/swift-open-redirection

This commit is contained in:
Paolo Tranquilli 2022-12-14 18:26:16 +01:00
Родитель 250ac686a2 33955ee4ab
Коммит 45c0c7fe6c
453 изменённых файлов: 23536 добавлений и 8431 удалений

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached
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
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached
newtype TAccessPathFrontOption =
TAccessPathFrontNone() or
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. */
class TypedContent extends MkTypedContent {
private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) }
}
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
}
/** An optional access path front. */

Просмотреть файл

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
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() }
/** 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 {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// 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() }
}
private class ValueNumberBound extends Bound {
IRBound::ValueNumberBound bound;
ValueNumberBound() { bound = this }
override string toString() { result = bound.toString() }
private class ValueNumberBound extends Bound instanceof IRBound::ValueNumberBound {
override string toString() { result = IRBound::ValueNumberBound.super.toString() }
}
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. */
private class ExplicitSignDef extends FlowSignDef {
SemSsaExplicitUpdate update;
ExplicitSignDef() { update = this }
final override Sign getSign() { result = semExprSign(update.getSourceExpr()) }
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
}
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
private class PhiSignDef extends FlowSignDef {
SemSsaPhiNode phi;
PhiSignDef() { phi = this }
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
final override Sign getSign() {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(phi, inp) and
edge.phiInput(this, inp) and
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.
*/
class FormatLiteral extends Literal {
FormatLiteral() {
exists(FormattingFunctionCall ffc | ffc.getFormat() = this) and
this instanceof StringLiteral
}
class FormatLiteral extends Literal instanceof StringLiteral {
FormatLiteral() { exists(FormattingFunctionCall ffc | ffc.getFormat() = this) }
/**
* 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).
*/
class Scanf extends ScanfFunction {
class Scanf extends ScanfFunction instanceof TopLevelFunction {
Scanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
this.hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...)
)
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
this.hasGlobalName("_wscanf_l")
}
override int getInputParameterIndex() { none() }
@ -49,15 +46,12 @@ class Scanf extends ScanfFunction {
/**
* The standard function `fscanf` (and variations).
*/
class Fscanf extends ScanfFunction {
class Fscanf extends ScanfFunction instanceof TopLevelFunction {
Fscanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
this.hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...)
)
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
this.hasGlobalName("_fwscanf_l")
}
override int getInputParameterIndex() { result = 0 }
@ -68,15 +62,12 @@ class Fscanf extends ScanfFunction {
/**
* The standard function `sscanf` (and variations).
*/
class Sscanf extends ScanfFunction {
class Sscanf extends ScanfFunction instanceof TopLevelFunction {
Sscanf() {
this instanceof TopLevelFunction and
(
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
this.hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...)
)
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
this.hasGlobalName("_swscanf_l")
}
override int getInputParameterIndex() { result = 0 }
@ -87,17 +78,12 @@ class Sscanf extends ScanfFunction {
/**
* The standard(ish) function `snscanf` (and variations).
*/
class Snscanf extends ScanfFunction {
class Snscanf extends ScanfFunction instanceof TopLevelFunction {
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_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.
)
this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
this.hasGlobalName("_snwscanf_l")
}
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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached
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
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached
newtype TAccessPathFrontOption =
TAccessPathFrontNone() or
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. */
class TypedContent extends MkTypedContent {
private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) }
}
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
}
/** An optional access path front. */

Просмотреть файл

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -296,6 +296,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
*/
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 {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// 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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached
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
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached
newtype TAccessPathFrontOption =
TAccessPathFrontNone() or
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. */
class TypedContent extends MkTypedContent {
private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) }
}
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
}
/** An optional access path front. */

Просмотреть файл

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
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() }
/** 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 {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// 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 }
}
class EndifDirective extends Directive {
EndifDirective() { this instanceof PreprocessorEndif }
class EndifDirective extends Directive instanceof PreprocessorEndif {
override int depthChange() { result = -1 }
override predicate mismatched() { depth() < 0 }

Просмотреть файл

@ -16,7 +16,7 @@
import cpp
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.dataflow.TaintTracking
import DataFlow::PathGraph
@ -47,12 +47,6 @@ class FileFunction extends FunctionWithWrappers {
override predicate interestingArg(int arg) { arg = 0 }
}
Expr asSourceExpr(DataFlow::Node node) {
result = node.asConvertedExpr()
or
result = node.asDefiningArgument()
}
Expr asSinkExpr(DataFlow::Node node) {
result =
node.asOperand()
@ -89,7 +83,7 @@ predicate hasUpperBoundsCheck(Variable var) {
class TaintedPathConfiguration extends TaintTracking::Configuration {
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) {
exists(FileFunction fileFunction |
@ -108,31 +102,16 @@ class TaintedPathConfiguration extends TaintTracking::Configuration {
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
FileFunction fileFunction, Expr taintedArg, Expr taintSource, TaintedPathConfiguration cfg,
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string taintCause, string callChain
FileFunction fileFunction, Expr taintedArg, FlowSource taintSource, TaintedPathConfiguration cfg,
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string callChain
where
taintedArg = asSinkExpr(sinkNode.getNode()) and
fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and
cfg.hasFilteredFlowPath(sourceNode, sinkNode) and
taintSource = asSourceExpr(sourceNode.getNode()) and
isUserInput(taintSource, taintCause)
cfg.hasFlowPath(sourceNode, sinkNode) and
taintSource = sourceNode.getNode()
select taintedArg, sourceNode, sinkNode,
"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
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox

Просмотреть файл

@ -639,3 +639,4 @@ postWithInFlow
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox

Просмотреть файл

@ -160,3 +160,4 @@ postWithInFlow
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox

Просмотреть файл

@ -1328,3 +1328,4 @@ postWithInFlow
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
uniqueParameterNodePosition
uniqueContentApprox

Просмотреть файл

@ -129,3 +129,4 @@ postWithInFlow
viableImplInCallContextTooLarge
uniqueParameterNodeAtPosition
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:738:24:738:24 | *e | Parameters with overlapping positions. |
uniqueParameterNodePosition
uniqueContentApprox

Просмотреть файл

@ -3,10 +3,8 @@ import Metrics.Dependencies.ExternalDependencies
/**
* Count directories as libraries for testing purposes.
*/
class TestPackage extends LibraryElement {
TestPackage() { this instanceof Folder }
override string getName() { result = this.(Folder).getBaseName() }
class TestPackage extends LibraryElement instanceof Folder {
override string getName() { result = super.getBaseName() }
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 |
subpaths
#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: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: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 |
nodes
| 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: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:43:17:43:24 | fileName | semmle.label | fileName |
| 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 |
subpaths
#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: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: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: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: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 (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 | scanf output argument | user input (value read by 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
Dapper,55,,,,,,,,,,55,,,,,
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,7,
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,
Microsoft.CSharp,,,24,,,,,,,,,,,,24,
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,15,
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62,
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12,
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16,
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10,
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,37,
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,8,
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,63,
Microsoft.Interop,,,27,,,,,,,,,,,,27,
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,1,
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,4,
Microsoft.VisualBasic,,,10,,,,,,,,,,,,5,5
Microsoft.Win32,,,8,,,,,,,,,,,,8,
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,
Newtonsoft.Json,,,91,,,,,,,,,,,,73,18
ServiceStack,194,,7,27,,,,,,75,92,,,,7,
System,65,4,12142,,8,8,9,,4,,33,3,1,3,10151,1991
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,
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,,,,,,
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,7,
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,,
Microsoft.CSharp,,,24,,,,,,,,,,,,,24,
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,,
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,15,
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,,45,1
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,,80,3
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,,62,
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,12,
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,,16,
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,,13,2
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,,16,1
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,10,
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,,37,
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,8,
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,,63,
Microsoft.Interop,,,27,,,,,,,,,,,,,27,
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,1,
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,,4,
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,5,5
Microsoft.Win32,,,8,,,,,,,,,,,,,8,
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,,
Newtonsoft.Json,,,91,,,,,,,,,,,,,73,18
ServiceStack,194,,7,27,,,,,,75,92,,,,,7,
System,65,8,12154,,8,8,9,,4,,33,3,1,3,4,10163,1991
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,

1 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
2 Dapper 55 55
3 JsonToItemsTaskFactory 7 7
4 Microsoft.ApplicationBlocks.Data 28 28
5 Microsoft.CSharp 24 24
6 Microsoft.EntityFrameworkCore 6 6
7 Microsoft.Extensions.Caching.Distributed 15 15
8 Microsoft.Extensions.Caching.Memory 46 45 1
9 Microsoft.Extensions.Configuration 83 80 3
10 Microsoft.Extensions.DependencyInjection 62 62
11 Microsoft.Extensions.DependencyModel 12 12
12 Microsoft.Extensions.FileProviders 16 16
13 Microsoft.Extensions.FileSystemGlobbing 15 13 2
14 Microsoft.Extensions.Hosting 17 16 1
15 Microsoft.Extensions.Http 10 10
16 Microsoft.Extensions.Logging 37 37
17 Microsoft.Extensions.Options 8 8
18 Microsoft.Extensions.Primitives 63 63
19 Microsoft.Interop 27 27
20 Microsoft.NET.Build.Tasks 1 1
21 Microsoft.NETCore.Platforms.BuildTasks 4 4
22 Microsoft.VisualBasic 10 5 5
23 Microsoft.Win32 8 8
24 MySql.Data.MySqlClient 48 48
25 Newtonsoft.Json 91 73 18
26 ServiceStack 194 7 27 75 92 7
27 System 65 4 8 12142 12154 8 8 9 4 33 3 1 3 4 10151 10163 1991
28 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`
`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,
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", 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", "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", "TextReader", True, "Read", "()", "", "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:
- 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:
pack: codeql/csharp-all
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)
}
/** Holds if this is a constructor without parameters. */
predicate isParameterless() { this.getNumberOfParameters() = 0 }
override string getUndecoratedName() { result = ".ctor" }
}

Просмотреть файл

@ -368,40 +368,32 @@ private Stmt getAnAssertingStmt(Assertion a) {
}
/** A method that forwards to a Boolean assertion method. */
class ForwarderBooleanAssertMethod extends BooleanAssertMethod {
private ForwarderAssertMethod forwarder;
class ForwarderBooleanAssertMethod extends BooleanAssertMethod instanceof ForwarderAssertMethod {
private BooleanAssertMethod underlying;
ForwarderBooleanAssertMethod() {
forwarder = this and
underlying = forwarder.getUnderlyingAssertMethod()
}
ForwarderBooleanAssertMethod() { underlying = super.getUnderlyingAssertMethod() }
override int getAnAssertionIndex(boolean b) {
forwarder.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
super.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
}
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. */
class ForwarderNullnessAssertMethod extends NullnessAssertMethod {
private ForwarderAssertMethod forwarder;
class ForwarderNullnessAssertMethod extends NullnessAssertMethod instanceof ForwarderAssertMethod {
private NullnessAssertMethod underlying;
ForwarderNullnessAssertMethod() {
forwarder = this and
underlying = forwarder.getUnderlyingAssertMethod()
}
ForwarderNullnessAssertMethod() { underlying = super.getUnderlyingAssertMethod() }
override int getAnAssertionIndex(boolean b) {
forwarder.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
super.getAForwarderAssertionIndex(result) = underlying.getAnAssertionIndex(b)
}
override AssertionFailure getAssertionFailure(int i) {
result = underlying.getAssertionFailure(forwarder.getAForwarderAssertionIndex(i))
result = underlying.getAssertionFailure(super.getAForwarderAssertionIndex(i))
}
}

Просмотреть файл

@ -338,7 +338,7 @@ module ModelValidation {
)
or
exists(string kind | sourceModel(_, _, _, _, _, _, _, kind, _) |
not kind = ["local", "file"] and
not kind = ["local", "remote", "file"] and
result = "Invalid kind \"" + kind + "\" in source model."
)
}

Просмотреть файл

@ -222,18 +222,14 @@ module ContentDataFlow {
)
}
private class ConfigurationAdapter extends DF::Configuration {
private Configuration c;
ConfigurationAdapter() { this = c }
private class ConfigurationAdapter extends DF::Configuration instanceof Configuration {
final override predicate isSource(Node source, DF::FlowState state) {
c.isSource(source) and
Configuration.super.isSource(source) and
state.(InitState).decode(true)
}
final override predicate isSink(Node sink, DF::FlowState state) {
c.isSink(sink) and
Configuration.super.isSink(sink) and
(
state instanceof InitState or
state instanceof StoreState or
@ -249,9 +245,9 @@ module ContentDataFlow {
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
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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached
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
newtype TAccessPathFront =
TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached
newtype TAccessPathFrontOption =
TAccessPathFrontNone() or
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. */
class TypedContent extends MkTypedContent {
private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) }
}
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
}
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
}
/** An optional access path front. */

Просмотреть файл

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
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 {
class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic]
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]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
}
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
kind = ret.getKind()
kind = ret.getKind() and
exists(argAp) and
exists(ap)
}
pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, 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 returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config);
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param
/* Begin: Stage logic. */
bindingset[result, apa]
private ApApprox unbindApa(ApApprox apa) {
pragma[only_bind_out](apa) = pragma[only_bind_out](result)
// use an alias as a workaround for bad functionality-induced joins
pragma[nomagic]
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]
private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind,
NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and
c = ret.getEnclosingCallable()
exists(ReturnKindExt kind |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
matchesCall(ccc, call)
)
}
/**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively.
*/
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(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
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
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and
exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc)
|
localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0
ap = ap0 and
apa = apa0
or
localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil
ap0 instanceof ApNil and
apa = getApprox(ap)
)
or
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
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
argAp = apNone() and
ap = getApNil(node)
ap = getApNil(node) and
apa = getApprox(ap)
)
or
// store
exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0)
ap = apCons(tc, ap0) and
apa = getApprox(ap)
)
or
// read
exists(Ap ap0, Content c |
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
// flow into a callable
exists(ApApprox apa |
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and
apa = getApprox(ap) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
or
// flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or
// flow through a callable
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)
)
}
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
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]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
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
getHeadContent(ap) = c
}
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
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]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config
ApApprox apa, Configuration config
) {
exists(
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc
|
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,
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
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),
config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind)
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
)
}
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
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]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition ppos |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and
p.isParameterOf(c, ppos) and
parameterFlowThroughAllowed(p, kind)
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
}
pragma[nomagic]
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 |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow,
exists(ApApprox argApa |
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
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
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
exists(ParamNodeEx p, boolean allowsFieldFlow |
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
returnCtx = TReturnCtxNone()
)
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) {
exists(NodeEx out, boolean allowsFieldFlow |
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()
)
}
/**
* 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]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state,
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
}
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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
pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
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)
}
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
parameterFlowsThroughRev(p, ap, kind, _, config)
)
}
pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) {
exists(ParamNodeEx p, Ap ap |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config)
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration 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]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic]
predicate localFlowBigStep(
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
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam {
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 ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
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]
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 {
import MkStage<Stage2>::Stage<Stage3Param>
private module Stage4 implements StageSig {
import MkStage<Stage3>::Stage<Stage4Param>
}
/**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) {
exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config)
)
}
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
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 =
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
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox =
TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _)
} or
TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and
Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _)
} or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) {
head = tc and
(
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) |
exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1)
or
len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or
exists(DataFlowType t |
len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and
Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t)
)
)
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
}
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage4;
class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
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,
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]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
}
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>;
private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result]
private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config)
)
}
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
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
p.isParameterOf(c, pos)
)
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config)
Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage5::revFlow(p, state, _, config)
)
}
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and
result =
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)
)
)
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result =
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) {
exists(TypedContent head |
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
) {
// A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and
Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and
(
if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) 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
TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 }
override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and
Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and
result.length() = len - 1
}
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head }
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) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
|
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
)
or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) {
ap0 = mid.getAp() 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
cc = mid.getCallContext()
}
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) {
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
cc = mid.getCallContext()
}
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) {
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
) {
exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and
Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos)
)
}
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
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
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 {

Просмотреть файл

@ -904,6 +904,13 @@ private module Cached {
TElementContent() or
TSyntheticFieldContent(SyntheticField f)
cached
newtype TContentApprox =
TFieldApproxContent(string firstChar) { firstChar = approximateFieldContent(_) } or
TPropertyApproxContent(string firstChar) { firstChar = approximatePropertyContent(_) } or
TElementApproxContent() or
TSyntheticFieldApproxContent()
pragma[nomagic]
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
not t1 instanceof Gvn::TypeParameterGvnType and
@ -2246,6 +2253,46 @@ predicate allowParameterReturnInSelf(ParameterNode 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,
* ensuring that they are visible to the taint tracking / data flow library.

Просмотреть файл

@ -257,9 +257,7 @@ class SystemNullReferenceExceptionClass extends SystemClass {
}
/** The `System.Object` class. */
class SystemObjectClass extends SystemClass {
SystemObjectClass() { this instanceof ObjectType }
class SystemObjectClass extends SystemClass instanceof ObjectType {
/** Gets the `Equals(object)` method. */
Method getEqualsMethod() {
result.getDeclaringType() = this and

Просмотреть файл

@ -56,6 +56,4 @@ class ProtectSanitizer extends Sanitizer {
/**
* An external location sink.
*/
class ExternalSink extends Sink {
ExternalSink() { this instanceof ExternalLocationSink }
}
class ExternalSink extends Sink instanceof ExternalLocationSink { }

Просмотреть файл

@ -38,14 +38,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/** A source of local user input. */
class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
class LocalSource extends Source instanceof LocalFlowSource { }
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }

Просмотреть файл

@ -36,9 +36,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/** The result of a reverse dns may be user-controlled. */
class ReverseDnsSource extends Source {

Просмотреть файл

@ -39,6 +39,4 @@ private class PrivateDataSource extends Source {
PrivateDataSource() { this.getExpr() instanceof PrivateDataExpr }
}
private class ExternalLocation extends Sink {
ExternalLocation() { this instanceof ExternalLocationSink }
}
private class ExternalLocation extends Sink instanceof ExternalLocationSink { }

Просмотреть файл

@ -17,8 +17,7 @@ abstract class SafeExternalApiCallable extends Callable { }
/** DEPRECATED: Alias for SafeExternalApiCallable */
deprecated class SafeExternalAPICallable = SafeExternalApiCallable;
private class SummarizedCallableSafe extends SafeExternalApiCallable {
SummarizedCallableSafe() { this instanceof SummarizedCallable }
private class SummarizedCallableSafe extends SafeExternalApiCallable instanceof SummarizedCallable {
}
/** The default set of "safe" external APIs. */

Просмотреть файл

@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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. */
private class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
private class RemoteSource extends Source instanceof RemoteFlowSource { }
private class HtmlSanitizer extends Sanitizer {
HtmlSanitizer() { this.asExpr() instanceof HtmlSanitizedExpr }

Просмотреть файл

@ -43,9 +43,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* A `pattern` argument to a construction of a `Regex`.

Просмотреть файл

@ -37,14 +37,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/** A source of local user input. */
class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
class LocalSource extends Source instanceof LocalFlowSource { }
/** An argument to the `ConnectionString` property on a data connection class. */
class SqlConnectionStringSink extends Sink {

Просмотреть файл

@ -38,14 +38,10 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/** A source of local user input. */
class LocalSource extends Source {
LocalSource() { this instanceof LocalFlowSource }
}
class LocalSource extends Source instanceof LocalFlowSource { }
/** An SQL expression passed to an API call that executes SQL. */
class SqlInjectionExprSink extends Sink {

Просмотреть файл

@ -39,9 +39,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* A path argument to a `File` method call.

Просмотреть файл

@ -44,9 +44,7 @@ abstract private class ConstructorOrStaticMethodSink extends Sink { }
*/
abstract class Sanitizer extends DataFlow::Node { }
private class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
private class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* User input to object method call deserialization flow tracking.

Просмотреть файл

@ -50,9 +50,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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 { }
private class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
private class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/** The `xpath` argument to an `XPathExpression.Compile(..)` call. */
class XPathExpressionCompileSink extends Sink {

Просмотреть файл

@ -149,9 +149,7 @@ class TaintTrackingConfiguration extends TaintTracking2::Configuration {
}
/** A source of remote user input. */
private class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
private class RemoteSource extends Source instanceof RemoteFlowSource { }
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }

Просмотреть файл

@ -27,9 +27,7 @@ private class ExternalXssSink extends Sink {
ExternalXssSink() { sinkNode(this, "xss") }
}
private class HtmlSinkSink extends Sink {
HtmlSinkSink() { this instanceof HtmlSink }
private class HtmlSinkSink extends Sink instanceof HtmlSink {
override string explanation() {
this instanceof WebPageWriteLiteralSink and
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.microsoft.Owin
private import semmle.code.csharp.frameworks.microsoft.AspNetCore
private import semmle.code.csharp.dataflow.ExternalFlow
/** A data flow source of remote user input. */
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" }
}
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.
*/
class SuppressionScope extends @commentline {
SuppressionScope() { this instanceof SuppressionComment }
class SuppressionScope extends @commentline instanceof SuppressionComment {
/** Gets a suppression comment with this scope. */
SuppressionComment getSuppressionComment() { result = this }
@ -60,7 +58,7 @@ class SuppressionScope extends @commentline {
predicate hasLocationInfo(
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. */

Просмотреть файл

@ -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.
*/
@ -31,7 +37,8 @@ class ExternalApi extends DotNet::Callable {
ExternalApi() {
this.isUnboundDeclaration() 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(), _)
}
/** 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. */
predicate isSource() {
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)

Просмотреть файл

@ -14,8 +14,7 @@ private predicate getRelevantUsages(string namespace, int usages) {
usages =
strictcount(Call c, ExternalApi api |
c.getTarget().getUnboundDeclaration() = api and
api.getNamespace() = namespace and
not api.isUninteresting()
api.getNamespace() = namespace
)
}

Просмотреть файл

@ -12,11 +12,8 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
private import ExternalApi
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

Просмотреть файл

@ -10,10 +10,7 @@ private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private predicate relevant(ExternalApi api) {
not api.isUninteresting() and
api.isSink()
}
private predicate relevant(ExternalApi api) { api.isSink() }
from string info, int usages
where Results<relevant/1>::restrict(info, usages)

Просмотреть файл

@ -10,10 +10,7 @@ private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private predicate relevant(ExternalApi api) {
not api.isUninteresting() and
api.isSource()
}
private predicate relevant(ExternalApi api) { api.isSource() }
from string info, int usages
where Results<relevant/1>::restrict(info, usages)

Просмотреть файл

@ -10,10 +10,7 @@ private import csharp
private import semmle.code.csharp.dispatch.Dispatch
private import ExternalApi
private predicate relevant(ExternalApi api) {
not api.isUninteresting() and
api.hasSummary()
}
private predicate relevant(ExternalApi api) { api.hasSummary() }
from string info, int 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 predicate relevant(ExternalApi api) {
not api.isUninteresting() and
not api.isSupported() and
not api instanceof FlowSummaryImpl::Public::NeutralCallable
}

Просмотреть файл

@ -51,9 +51,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
}
/** A source of remote user input. */
class RemoteSource extends Source {
RemoteSource() { this instanceof RemoteFlowSource }
}
class RemoteSource extends Source instanceof RemoteFlowSource { }
/**
* 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
* for Server Side Request Forgery(SSRF) Vulnerabilities.
*/
private class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
private class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { }
/**
* An url argument to a `HttpRequestMessage` constructor call

Просмотреть файл

@ -16,7 +16,6 @@ private import Telemetry.ExternalApi
from Call c, ExternalApi api
where
c.getTarget().getUnboundDeclaration() = api and
not api.isUninteresting() and
not api.isSupported() and
not api instanceof FlowSummaryImpl::Public::NeutralCallable
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
not api instanceof CS::ConversionOperator 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 Common
class TTConfig extends TaintTracking::Configuration {
Config c;
class TTConfig extends TaintTracking::Configuration instanceof Config {
override predicate isSource(DataFlow::Node source) { Config.super.isSource(source) }
TTConfig() { this = c }
override predicate isSource(DataFlow::Node source) { c.isSource(source) }
override predicate isSink(DataFlow::Node sink) { c.isSink(sink) }
override predicate isSink(DataFlow::Node sink) { Config.super.isSink(sink) }
}
from TTConfig c, DataFlow::Node source, DataFlow::Node sink

Просмотреть файл

@ -6,14 +6,10 @@ import csharp
import Common
import DataFlow::PathGraph
class TTConfig extends TaintTracking::Configuration {
Config c;
class TTConfig extends TaintTracking::Configuration instanceof Config {
override predicate isSource(DataFlow::Node source) { Config.super.isSource(source) }
TTConfig() { this = c }
override predicate isSource(DataFlow::Node source) { c.isSource(source) }
override predicate isSink(DataFlow::Node sink) { c.isSink(sink) }
override predicate isSink(DataFlow::Node sink) { Config.super.isSink(sink) }
}
from TTConfig c, DataFlow::PathNode source, DataFlow::PathNode sink, string s

Просмотреть файл

@ -6,9 +6,7 @@ private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
IncludeAllSummarizedCallable() { exists(this) }
}
private class IncludeNeutralCallable extends RelevantNeutralCallable {
IncludeNeutralCallable() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
private class IncludeNeutralCallable extends RelevantNeutralCallable instanceof FlowSummaryImpl::Public::NeutralCallable {
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
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.ExternalFlow
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
IncludeFilteredSummarizedCallable() { this instanceof SummarizedCallable }
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable instanceof SummarizedCallable {
/**
* Holds if flow is propagated between `input` and `output` and
* 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(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
this.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and
super.propagatesFlow(input, output, preservesValue) and
not exists(IncludeSummarizedCallable rsc |
isBaseCallableOrPrototype(rsc) and
rsc.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and

Просмотреть файл

@ -2,8 +2,7 @@ import semmle.code.csharp.frameworks.EntityFramework::EntityFramework
import shared.FlowSummaries
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable {
IncludeEFSummarizedCallable() { this instanceof EFSummarizedCallable }
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable instanceof EFSummarizedCallable {
}
query predicate sourceNode(DataFlow::Node node, string kind) {

Просмотреть файл

@ -131,4 +131,15 @@ public class CollectionFlow
{
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
cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess()
select cmp, "Overflow check."
select cmp, "Overflow check."

Просмотреть файл

@ -6,4 +6,4 @@ where
cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess() and
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
forall(Expr op | op = a.getAnOperand() | isSmall(op)) and
not isSmall(a.getExplicitlyConverted())
select cmp, "Bad overflow check"
select cmp, "Bad overflow check"

Просмотреть файл

@ -1,8 +1,9 @@
import cpp
from FunctionCall alloc, FunctionCall free, LocalScopeVariable v
where allocationCall(alloc)
and alloc = v.getAnAssignedValue()
and freeCall(free, v.getAnAccess())
and alloc.getASuccessor+() = free
where
allocationCall(alloc) and
alloc = v.getAnAssignedValue() and
freeCall(free, v.getAnAccess()) and
alloc.getASuccessor+() = free
select alloc, free

Просмотреть файл

@ -1,8 +1,9 @@
import cpp
from FunctionCall free, LocalScopeVariable v, VariableAccess u
where freeCall(free, v.getAnAccess())
and u = v.getAnAccess()
and u.isRValue()
and free.getASuccessor+() = u
select free, u
where
freeCall(free, v.getAnAccess()) and
u = v.getAnAccess() and
u.isRValue() and
free.getASuccessor+() = u
select free, u

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше