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 { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind) TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
TypedContent getATypedContent(TypedContentApprox c) {
exists(ContentApprox cls, DataFlowType t, Content cont |
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
cls = getContentApprox(cont)
)
}
cached cached
newtype TAccessPathFront = newtype TAccessPathFront =
TFrontNil(DataFlowType t) or TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc) TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached cached
newtype TAccessPathFrontOption = newtype TAccessPathFrontOption =
TAccessPathFrontNone() or TAccessPathFrontNone() or
TAccessPathFrontSome(AccessPathFront apf) TAccessPathFrontSome(AccessPathFront apf)
cached
newtype TApproxAccessPathFrontOption =
TApproxAccessPathFrontNone() or
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
} }
/** /**
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
} }
} }
/** An approximated `Content` tagged with the type of a containing object. */
class TypedContentApprox extends MkTypedContentApprox {
private ContentApprox c;
private DataFlowType t;
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
/** Gets a typed content approximated by this value. */
TypedContent getATypedContent() { result = getATypedContent(this) }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this approximated content. */
string toString() { result = c.toString() }
}
/**
* The front of an approximated access path. This is either a head or a nil.
*/
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
abstract string toString();
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
pragma[nomagic]
TypedContent getAHead() {
exists(TypedContentApprox cont |
this = TApproxFrontHead(cont) and
result = cont.getATypedContent()
)
}
}
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
private DataFlowType t;
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
private TypedContentApprox tc;
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}
/** An optional approximated access path front. */
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
string toString() {
this = TApproxAccessPathFrontNone() and result = "<none>"
or
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType(); abstract DataFlowType getType();
abstract boolean toBoolNonEmpty(); abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
} }
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t } override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false } override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
} }
class AccessPathFrontHead extends AccessPathFront, TFrontHead { class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() } override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true } override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
} }
/** An optional access path front. */ /** An optional access path front. */

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

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions." msg = "Parameter node with multiple positions."
} }
query predicate uniqueContentApprox(Content c, string msg) {
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
msg = "Non-unique content approximation."
}
} }

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

@ -551,6 +551,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
*/ */
predicate allowParameterReturnInSelf(ParameterNode p) { none() } predicate allowParameterReturnInSelf(ParameterNode p) { none() }
/** An approximated `Content`. */
class ContentApprox = Unit;
/** Gets an approximated value for content `c`. */
pragma[inline]
ContentApprox getContentApprox(Content c) { any() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration { private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) { override predicate argHasPostUpdateExclude(ArgumentNode n) {
// The rules for whether an IR argument gets a post-update node are too // The rules for whether an IR argument gets a post-update node are too

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

@ -292,12 +292,8 @@ module SemanticExprConfig {
final Location getLocation() { result = super.getLocation() } final Location getLocation() { result = super.getLocation() }
} }
private class ValueNumberBound extends Bound { private class ValueNumberBound extends Bound instanceof IRBound::ValueNumberBound {
IRBound::ValueNumberBound bound; override string toString() { result = IRBound::ValueNumberBound.super.toString() }
ValueNumberBound() { bound = this }
override string toString() { result = bound.toString() }
} }
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound } predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }

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

@ -33,23 +33,15 @@ abstract private class FlowSignDef extends SignDef {
} }
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */ /** An SSA definition whose sign is determined by the sign of that definitions source expression. */
private class ExplicitSignDef extends FlowSignDef { private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
SemSsaExplicitUpdate update; final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
ExplicitSignDef() { update = this }
final override Sign getSign() { result = semExprSign(update.getSourceExpr()) }
} }
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */ /** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
private class PhiSignDef extends FlowSignDef { private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
SemSsaPhiNode phi;
PhiSignDef() { phi = this }
final override Sign getSign() { final override Sign getSign() {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(phi, inp) and edge.phiInput(this, inp) and
result = semSsaSign(inp, edge) result = semSsaSign(inp, edge)
) )
} }

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

@ -397,11 +397,8 @@ private int lengthInBase16(float f) {
/** /**
* A class to represent format strings that occur as arguments to invocations of formatting functions. * A class to represent format strings that occur as arguments to invocations of formatting functions.
*/ */
class FormatLiteral extends Literal { class FormatLiteral extends Literal instanceof StringLiteral {
FormatLiteral() { FormatLiteral() { exists(FormattingFunctionCall ffc | ffc.getFormat() = this) }
exists(FormattingFunctionCall ffc | ffc.getFormat() = this) and
this instanceof StringLiteral
}
/** /**
* Gets the function call where this format string is used. * Gets the function call where this format string is used.

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

@ -30,15 +30,12 @@ abstract class ScanfFunction extends Function {
/** /**
* The standard function `scanf` (and variations). * The standard function `scanf` (and variations).
*/ */
class Scanf extends ScanfFunction { class Scanf extends ScanfFunction instanceof TopLevelFunction {
Scanf() { Scanf() {
this instanceof TopLevelFunction and this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...)
( this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...)
this.hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...) this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
this.hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...) this.hasGlobalName("_wscanf_l")
this.hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...)
this.hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...)
)
} }
override int getInputParameterIndex() { none() } override int getInputParameterIndex() { none() }
@ -49,15 +46,12 @@ class Scanf extends ScanfFunction {
/** /**
* The standard function `fscanf` (and variations). * The standard function `fscanf` (and variations).
*/ */
class Fscanf extends ScanfFunction { class Fscanf extends ScanfFunction instanceof TopLevelFunction {
Fscanf() { Fscanf() {
this instanceof TopLevelFunction and this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...)
( this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...)
this.hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...) this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
this.hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...) this.hasGlobalName("_fwscanf_l")
this.hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...)
this.hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...)
)
} }
override int getInputParameterIndex() { result = 0 } override int getInputParameterIndex() { result = 0 }
@ -68,15 +62,12 @@ class Fscanf extends ScanfFunction {
/** /**
* The standard function `sscanf` (and variations). * The standard function `sscanf` (and variations).
*/ */
class Sscanf extends ScanfFunction { class Sscanf extends ScanfFunction instanceof TopLevelFunction {
Sscanf() { Sscanf() {
this instanceof TopLevelFunction and this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...)
( this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...)
this.hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...) this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
this.hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...) this.hasGlobalName("_swscanf_l")
this.hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...)
this.hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...)
)
} }
override int getInputParameterIndex() { result = 0 } override int getInputParameterIndex() { result = 0 }
@ -87,17 +78,12 @@ class Sscanf extends ScanfFunction {
/** /**
* The standard(ish) function `snscanf` (and variations). * The standard(ish) function `snscanf` (and variations).
*/ */
class Snscanf extends ScanfFunction { class Snscanf extends ScanfFunction instanceof TopLevelFunction {
Snscanf() { Snscanf() {
this instanceof TopLevelFunction and this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...)
( this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...)
this.hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...) this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
this.hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) this.hasGlobalName("_snwscanf_l")
this.hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...)
this.hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...)
// note that the max_amount is not a limit on the output length, it's an input length
// limit used with non null-terminated strings.
)
} }
override int getInputParameterIndex() { result = 0 } override int getInputParameterIndex() { result = 0 }

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind) TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
TypedContent getATypedContent(TypedContentApprox c) {
exists(ContentApprox cls, DataFlowType t, Content cont |
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
cls = getContentApprox(cont)
)
}
cached cached
newtype TAccessPathFront = newtype TAccessPathFront =
TFrontNil(DataFlowType t) or TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc) TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached cached
newtype TAccessPathFrontOption = newtype TAccessPathFrontOption =
TAccessPathFrontNone() or TAccessPathFrontNone() or
TAccessPathFrontSome(AccessPathFront apf) TAccessPathFrontSome(AccessPathFront apf)
cached
newtype TApproxAccessPathFrontOption =
TApproxAccessPathFrontNone() or
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
} }
/** /**
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
} }
} }
/** An approximated `Content` tagged with the type of a containing object. */
class TypedContentApprox extends MkTypedContentApprox {
private ContentApprox c;
private DataFlowType t;
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
/** Gets a typed content approximated by this value. */
TypedContent getATypedContent() { result = getATypedContent(this) }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this approximated content. */
string toString() { result = c.toString() }
}
/**
* The front of an approximated access path. This is either a head or a nil.
*/
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
abstract string toString();
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
pragma[nomagic]
TypedContent getAHead() {
exists(TypedContentApprox cont |
this = TApproxFrontHead(cont) and
result = cont.getATypedContent()
)
}
}
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
private DataFlowType t;
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
private TypedContentApprox tc;
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}
/** An optional approximated access path front. */
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
string toString() {
this = TApproxAccessPathFrontNone() and result = "<none>"
or
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType(); abstract DataFlowType getType();
abstract boolean toBoolNonEmpty(); abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
} }
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t } override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false } override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
} }
class AccessPathFrontHead extends AccessPathFront, TFrontHead { class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() } override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true } override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
} }
/** An optional access path front. */ /** An optional access path front. */

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

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions." msg = "Parameter node with multiple positions."
} }
query predicate uniqueContentApprox(Content c, string msg) {
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
msg = "Non-unique content approximation."
}
} }

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -296,6 +296,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
*/ */
predicate allowParameterReturnInSelf(ParameterNode p) { none() } predicate allowParameterReturnInSelf(ParameterNode p) { none() }
/** An approximated `Content`. */
class ContentApprox = Unit;
/** Gets an approximated value for content `c`. */
pragma[inline]
ContentApprox getContentApprox(Content c) { any() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration { private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) { override predicate argHasPostUpdateExclude(ArgumentNode n) {
// Is the null pointer (or something that's not really a pointer) // Is the null pointer (or something that's not really a pointer)

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind) TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
TypedContent getATypedContent(TypedContentApprox c) {
exists(ContentApprox cls, DataFlowType t, Content cont |
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
cls = getContentApprox(cont)
)
}
cached cached
newtype TAccessPathFront = newtype TAccessPathFront =
TFrontNil(DataFlowType t) or TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc) TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached cached
newtype TAccessPathFrontOption = newtype TAccessPathFrontOption =
TAccessPathFrontNone() or TAccessPathFrontNone() or
TAccessPathFrontSome(AccessPathFront apf) TAccessPathFrontSome(AccessPathFront apf)
cached
newtype TApproxAccessPathFrontOption =
TApproxAccessPathFrontNone() or
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
} }
/** /**
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
} }
} }
/** An approximated `Content` tagged with the type of a containing object. */
class TypedContentApprox extends MkTypedContentApprox {
private ContentApprox c;
private DataFlowType t;
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
/** Gets a typed content approximated by this value. */
TypedContent getATypedContent() { result = getATypedContent(this) }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this approximated content. */
string toString() { result = c.toString() }
}
/**
* The front of an approximated access path. This is either a head or a nil.
*/
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
abstract string toString();
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
pragma[nomagic]
TypedContent getAHead() {
exists(TypedContentApprox cont |
this = TApproxFrontHead(cont) and
result = cont.getATypedContent()
)
}
}
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
private DataFlowType t;
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
private TypedContentApprox tc;
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}
/** An optional approximated access path front. */
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
string toString() {
this = TApproxAccessPathFrontNone() and result = "<none>"
or
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType(); abstract DataFlowType getType();
abstract boolean toBoolNonEmpty(); abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
} }
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t } override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false } override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
} }
class AccessPathFrontHead extends AccessPathFront, TFrontHead { class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() } override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true } override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
} }
/** An optional access path front. */ /** An optional access path front. */

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

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions." msg = "Parameter node with multiple positions."
} }
query predicate uniqueContentApprox(Content c, string msg) {
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
msg = "Non-unique content approximation."
}
} }

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

@ -400,6 +400,13 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
*/ */
predicate allowParameterReturnInSelf(ParameterNode p) { none() } predicate allowParameterReturnInSelf(ParameterNode p) { none() }
/** An approximated `Content`. */
class ContentApprox = Unit;
/** Gets an approximated value for content `c`. */
pragma[inline]
ContentApprox getContentApprox(Content c) { any() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration { private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) { override predicate argHasPostUpdateExclude(ArgumentNode n) {
// The rules for whether an IR argument gets a post-update node are too // The rules for whether an IR argument gets a post-update node are too

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

@ -66,9 +66,7 @@ class ElseDirective extends Directive {
override predicate mismatched() { depth() < 1 } override predicate mismatched() { depth() < 1 }
} }
class EndifDirective extends Directive { class EndifDirective extends Directive instanceof PreprocessorEndif {
EndifDirective() { this instanceof PreprocessorEndif }
override int depthChange() { result = -1 } override int depthChange() { result = -1 }
override predicate mismatched() { depth() < 0 } override predicate mismatched() { depth() < 0 }

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

@ -16,7 +16,7 @@
import cpp import cpp
import semmle.code.cpp.security.FunctionWithWrappers import semmle.code.cpp.security.FunctionWithWrappers
import semmle.code.cpp.security.Security import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking import semmle.code.cpp.ir.dataflow.TaintTracking
import DataFlow::PathGraph import DataFlow::PathGraph
@ -47,12 +47,6 @@ class FileFunction extends FunctionWithWrappers {
override predicate interestingArg(int arg) { arg = 0 } override predicate interestingArg(int arg) { arg = 0 }
} }
Expr asSourceExpr(DataFlow::Node node) {
result = node.asConvertedExpr()
or
result = node.asDefiningArgument()
}
Expr asSinkExpr(DataFlow::Node node) { Expr asSinkExpr(DataFlow::Node node) {
result = result =
node.asOperand() node.asOperand()
@ -89,7 +83,7 @@ predicate hasUpperBoundsCheck(Variable var) {
class TaintedPathConfiguration extends TaintTracking::Configuration { class TaintedPathConfiguration extends TaintTracking::Configuration {
TaintedPathConfiguration() { this = "TaintedPathConfiguration" } TaintedPathConfiguration() { this = "TaintedPathConfiguration" }
override predicate isSource(DataFlow::Node node) { isUserInput(asSourceExpr(node), _) } override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
override predicate isSink(DataFlow::Node node) { override predicate isSink(DataFlow::Node node) {
exists(FileFunction fileFunction | exists(FileFunction fileFunction |
@ -108,31 +102,16 @@ class TaintedPathConfiguration extends TaintTracking::Configuration {
hasUpperBoundsCheck(checkedVar) hasUpperBoundsCheck(checkedVar)
) )
} }
predicate hasFilteredFlowPath(DataFlow::PathNode source, DataFlow::PathNode sink) {
this.hasFlowPath(source, sink) and
// The use of `isUserInput` in `isSink` in combination with `asSourceExpr` causes
// duplicate results. Filter these duplicates. The proper solution is to switch to
// using `LocalFlowSource` and `RemoteFlowSource`, but this currently only supports
// a subset of the cases supported by `isUserInput`.
not exists(DataFlow::PathNode source2 |
this.hasFlowPath(source2, sink) and
asSourceExpr(source.getNode()) = asSourceExpr(source2.getNode())
|
not exists(source.getNode().asConvertedExpr()) and exists(source2.getNode().asConvertedExpr())
)
}
} }
from from
FileFunction fileFunction, Expr taintedArg, Expr taintSource, TaintedPathConfiguration cfg, FileFunction fileFunction, Expr taintedArg, FlowSource taintSource, TaintedPathConfiguration cfg,
DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string taintCause, string callChain DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode, string callChain
where where
taintedArg = asSinkExpr(sinkNode.getNode()) and taintedArg = asSinkExpr(sinkNode.getNode()) and
fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and fileFunction.outermostWrapperFunctionCall(taintedArg, callChain) and
cfg.hasFilteredFlowPath(sourceNode, sinkNode) and cfg.hasFlowPath(sourceNode, sinkNode) and
taintSource = asSourceExpr(sourceNode.getNode()) and taintSource = sourceNode.getNode()
isUserInput(taintSource, taintCause)
select taintedArg, sourceNode, sinkNode, select taintedArg, sourceNode, sinkNode,
"This argument to a file access function is derived from $@ and then passed to " + callChain + ".", "This argument to a file access function is derived from $@ and then passed to " + callChain + ".",
taintSource, "user input (" + taintCause + ")" taintSource, "user input (" + taintSource.getSourceType() + ")"

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

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

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

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

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

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

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

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

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

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

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

@ -2717,3 +2717,4 @@ uniqueParameterNodeAtPosition
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:735:22:735:22 | *s | Parameters with overlapping positions. | | ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:735:22:735:22 | *s | Parameters with overlapping positions. |
| ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:738:24:738:24 | *e | Parameters with overlapping positions. | | ir.cpp:724:6:724:13 | TryCatch | 0 | ir.cpp:738:24:738:24 | *e | Parameters with overlapping positions. |
uniqueParameterNodePosition uniqueParameterNodePosition
uniqueContentApprox

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

@ -3,10 +3,8 @@ import Metrics.Dependencies.ExternalDependencies
/** /**
* Count directories as libraries for testing purposes. * Count directories as libraries for testing purposes.
*/ */
class TestPackage extends LibraryElement { class TestPackage extends LibraryElement instanceof Folder {
TestPackage() { this instanceof Folder } override string getName() { result = super.getBaseName() }
override string getName() { result = this.(Folder).getBaseName() }
override string getVersion() { result = "1.0" } override string getVersion() { result = "1.0" }

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

@ -5,4 +5,4 @@ nodes
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | semmle.label | data indirection |
subpaths subpaths
#select #select
| CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | ... + ... | user input (fgets) | | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:77:23:77:26 | data indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | CWE23_Relative_Path_Traversal__char_console_fopen_11.cpp:55:27:55:38 | fgets output argument | user input (string read by fgets) |

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

@ -2,7 +2,6 @@ edges
| test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection |
| test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection | | test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection |
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection | | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection |
| test.c:43:17:43:24 | fileName | test.c:44:11:44:18 | fileName indirection |
| test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection | | test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection |
nodes nodes
| test.c:9:23:9:26 | argv | semmle.label | argv | | test.c:9:23:9:26 | argv | semmle.label | argv |
@ -11,12 +10,11 @@ nodes
| test.c:32:11:32:18 | fileName indirection | semmle.label | fileName indirection | | test.c:32:11:32:18 | fileName indirection | semmle.label | fileName indirection |
| test.c:37:17:37:24 | scanf output argument | semmle.label | scanf output argument | | test.c:37:17:37:24 | scanf output argument | semmle.label | scanf output argument |
| test.c:38:11:38:18 | fileName indirection | semmle.label | fileName indirection | | test.c:38:11:38:18 | fileName indirection | semmle.label | fileName indirection |
| test.c:43:17:43:24 | fileName | semmle.label | fileName |
| test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument | | test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument |
| test.c:44:11:44:18 | fileName indirection | semmle.label | fileName indirection | | test.c:44:11:44:18 | fileName indirection | semmle.label | fileName indirection |
subpaths subpaths
#select #select
| test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (argv) | | test.c:17:11:17:18 | fileName | test.c:9:23:9:26 | argv | test.c:17:11:17:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:9:23:9:26 | argv | user input (a command-line argument) |
| test.c:32:11:32:18 | fileName | test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:31:22:31:25 | argv | user input (argv) | | test.c:32:11:32:18 | fileName | test.c:31:22:31:25 | argv | test.c:32:11:32:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:31:22:31:25 | argv | user input (a command-line argument) |
| test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | fileName | user input (scanf) | | test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | scanf output argument | user input (value read by scanf) |
| test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | fileName | test.c:44:11:44:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | fileName | user input (scanf) | | test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | fileName indirection | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | scanf output argument | user input (value read by scanf) |

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

@ -1,28 +1,28 @@
package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:local,summary:taint,summary:value package,sink,source,summary,sink:code,sink:encryption-decryptor,sink:encryption-encryptor,sink:encryption-keyprop,sink:encryption-symmetrickey,sink:html,sink:remote,sink:sql,sink:xss,source:file,source:local,source:remote,summary:taint,summary:value
Dapper,55,,,,,,,,,,55,,,,, Dapper,55,,,,,,,,,,55,,,,,,
JsonToItemsTaskFactory,,,7,,,,,,,,,,,,7, JsonToItemsTaskFactory,,,7,,,,,,,,,,,,,7,
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,, Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,28,,,,,,
Microsoft.CSharp,,,24,,,,,,,,,,,,24, Microsoft.CSharp,,,24,,,,,,,,,,,,,24,
Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,, Microsoft.EntityFrameworkCore,6,,,,,,,,,,6,,,,,,
Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,15, Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,,,,,,,15,
Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,45,1 Microsoft.Extensions.Caching.Memory,,,46,,,,,,,,,,,,,45,1
Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,80,3 Microsoft.Extensions.Configuration,,,83,,,,,,,,,,,,,80,3
Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,62, Microsoft.Extensions.DependencyInjection,,,62,,,,,,,,,,,,,62,
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,12, Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,12,
Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,16, Microsoft.Extensions.FileProviders,,,16,,,,,,,,,,,,,16,
Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,13,2 Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,,,,,,,13,2
Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,16,1 Microsoft.Extensions.Hosting,,,17,,,,,,,,,,,,,16,1
Microsoft.Extensions.Http,,,10,,,,,,,,,,,,10, Microsoft.Extensions.Http,,,10,,,,,,,,,,,,,10,
Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,37, Microsoft.Extensions.Logging,,,37,,,,,,,,,,,,,37,
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,8, Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,8,
Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,63, Microsoft.Extensions.Primitives,,,63,,,,,,,,,,,,,63,
Microsoft.Interop,,,27,,,,,,,,,,,,27, Microsoft.Interop,,,27,,,,,,,,,,,,,27,
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,1, Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,1,
Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,4, Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,,,,,,,4,
Microsoft.VisualBasic,,,10,,,,,,,,,,,,5,5 Microsoft.VisualBasic,,,10,,,,,,,,,,,,,5,5
Microsoft.Win32,,,8,,,,,,,,,,,,8, Microsoft.Win32,,,8,,,,,,,,,,,,,8,
MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,, MySql.Data.MySqlClient,48,,,,,,,,,,48,,,,,,
Newtonsoft.Json,,,91,,,,,,,,,,,,73,18 Newtonsoft.Json,,,91,,,,,,,,,,,,,73,18
ServiceStack,194,,7,27,,,,,,75,92,,,,7, ServiceStack,194,,7,27,,,,,,75,92,,,,,7,
System,65,4,12142,,8,8,9,,4,,33,3,1,3,10151,1991 System,65,8,12154,,8,8,9,,4,,33,3,1,3,4,10163,1991
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,, Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,

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` Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194, `ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
System,"``System.*``, ``System``",4,12142,65,7 System,"``System.*``, ``System``",8,12154,65,7
Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138, Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``Windows.Security.Cryptography.Core``",,556,138,
Totals,,4,12705,397,7 Totals,,8,12717,397,7

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

@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added tcp/upd sockets as taint sources.

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

@ -57,7 +57,19 @@ extensions:
- ["System.IO", "Stream", True, "Write", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "Stream", True, "Write", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
- ["System.IO", "Stream", False, "WriteAsync", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "Stream", False, "WriteAsync", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
- ["System.IO", "Stream", True, "WriteAsync", "(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"] - ["System.IO", "Stream", True, "WriteAsync", "(System.Byte[],System.Int32,System.Int32,System.Threading.CancellationToken)", "", "Argument[0].Element", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean,System.IO.FileStreamOptions)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean,System.Int32)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean,System.Int32,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.IO.FileStreamOptions)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Text.Encoding)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.IO.Stream,System.Boolean)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StreamReader", False, "StreamReader", "(System.String,System.Text.Encoding)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "StringReader", False, "StringReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"] - ["System.IO", "StringReader", False, "StringReader", "(System.String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["System.IO", "TextReader", True, "Read", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["System.IO", "TextReader", True, "Read", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["System.IO", "TextReader", True, "Read", "(System.Char[],System.Int32,System.Int32)", "", "Argument[this]", "ReturnValue", "taint", "manual"] - ["System.IO", "TextReader", True, "Read", "(System.Char[],System.Int32,System.Int32)", "", "Argument[this]", "ReturnValue", "taint", "manual"]

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

@ -1,4 +1,12 @@
extensions: extensions:
- addsTo:
pack: codeql/csharp-all
extensible: extSourceModel
data:
- ["System.Net.Sockets", "TcpClient", False, "GetStream", "", "", "ReturnValue", "remote", "manual"]
- ["System.Net.Sockets", "UpdClient", False, "EndReceive", "", "", "ReturnValue", "remote", "manual"]
- ["System.Net.Sockets", "UpdClient", False, "Receive", "", "", "ReturnValue", "remote", "manual"]
- ["System.Net.Sockets", "UpdClient", False, "ReceiveAsync", "", "", "ReturnValue", "remote", "manual"]
- addsTo: - addsTo:
pack: codeql/csharp-all pack: codeql/csharp-all
extensible: extSummaryModel extensible: extSummaryModel

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

@ -358,6 +358,9 @@ class Constructor extends DotNet::Constructor, Callable, Member, Attributable, @
if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1) if this.isStatic() then result = this.getParameter(i) else result = this.getParameter(i - 1)
} }
/** Holds if this is a constructor without parameters. */
predicate isParameterless() { this.getNumberOfParameters() = 0 }
override string getUndecoratedName() { result = ".ctor" } override string getUndecoratedName() { result = ".ctor" }
} }

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

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

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

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

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

@ -222,18 +222,14 @@ module ContentDataFlow {
) )
} }
private class ConfigurationAdapter extends DF::Configuration { private class ConfigurationAdapter extends DF::Configuration instanceof Configuration {
private Configuration c;
ConfigurationAdapter() { this = c }
final override predicate isSource(Node source, DF::FlowState state) { final override predicate isSource(Node source, DF::FlowState state) {
c.isSource(source) and Configuration.super.isSource(source) and
state.(InitState).decode(true) state.(InitState).decode(true)
} }
final override predicate isSink(Node sink, DF::FlowState state) { final override predicate isSink(Node sink, DF::FlowState state) {
c.isSink(sink) and Configuration.super.isSink(sink) and
( (
state instanceof InitState or state instanceof InitState or
state instanceof StoreState or state instanceof StoreState or
@ -249,9 +245,9 @@ module ContentDataFlow {
additionalStep(node1, state1, node2, state2, this) additionalStep(node1, state1, node2, state2, this)
} }
final override predicate isBarrier(Node node) { c.isBarrier(node) } final override predicate isBarrier(Node node) { Configuration.super.isBarrier(node) }
final override FlowFeature getAFeature() { result = c.getAFeature() } final override FlowFeature getAFeature() { result = Configuration.super.getAFeature() }
// needed to record reads/stores inside summarized callables // needed to record reads/stores inside summarized callables
final override predicate includeHiddenNodes() { any() } final override predicate includeHiddenNodes() { any() }

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -926,18 +926,46 @@ private module Cached {
TReturnCtxNoFlowThrough() or TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind) TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
cached
newtype TTypedContentApprox =
MkTypedContentApprox(ContentApprox c, DataFlowType t) {
exists(Content cont |
c = getContentApprox(cont) and
store(_, cont, _, _, t)
)
}
cached cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) } newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
cached
TypedContent getATypedContent(TypedContentApprox c) {
exists(ContentApprox cls, DataFlowType t, Content cont |
c = MkTypedContentApprox(cls, pragma[only_bind_into](t)) and
result = MkTypedContent(cont, pragma[only_bind_into](t)) and
cls = getContentApprox(cont)
)
}
cached cached
newtype TAccessPathFront = newtype TAccessPathFront =
TFrontNil(DataFlowType t) or TFrontNil(DataFlowType t) or
TFrontHead(TypedContent tc) TFrontHead(TypedContent tc)
cached
newtype TApproxAccessPathFront =
TApproxFrontNil(DataFlowType t) or
TApproxFrontHead(TypedContentApprox tc)
cached cached
newtype TAccessPathFrontOption = newtype TAccessPathFrontOption =
TAccessPathFrontNone() or TAccessPathFrontNone() or
TAccessPathFrontSome(AccessPathFront apf) TAccessPathFrontSome(AccessPathFront apf)
cached
newtype TApproxAccessPathFrontOption =
TApproxAccessPathFrontNone() or
TApproxAccessPathFrontSome(ApproxAccessPathFront apf)
} }
/** /**
@ -1353,6 +1381,75 @@ class ReturnCtx extends TReturnCtx {
} }
} }
/** An approximated `Content` tagged with the type of a containing object. */
class TypedContentApprox extends MkTypedContentApprox {
private ContentApprox c;
private DataFlowType t;
TypedContentApprox() { this = MkTypedContentApprox(c, t) }
/** Gets a typed content approximated by this value. */
TypedContent getATypedContent() { result = getATypedContent(this) }
/** Gets the container type. */
DataFlowType getContainerType() { result = t }
/** Gets a textual representation of this approximated content. */
string toString() { result = c.toString() }
}
/**
* The front of an approximated access path. This is either a head or a nil.
*/
abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
abstract string toString();
abstract DataFlowType getType();
abstract boolean toBoolNonEmpty();
pragma[nomagic]
TypedContent getAHead() {
exists(TypedContentApprox cont |
this = TApproxFrontHead(cont) and
result = cont.getATypedContent()
)
}
}
class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil {
private DataFlowType t;
ApproxAccessPathFrontNil() { this = TApproxFrontNil(t) }
override string toString() { result = ppReprType(t) }
override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false }
}
class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead {
private TypedContentApprox tc;
ApproxAccessPathFrontHead() { this = TApproxFrontHead(tc) }
override string toString() { result = tc.toString() }
override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true }
}
/** An optional approximated access path front. */
class ApproxAccessPathFrontOption extends TApproxAccessPathFrontOption {
string toString() {
this = TApproxAccessPathFrontNone() and result = "<none>"
or
this = TApproxAccessPathFrontSome(any(ApproxAccessPathFront apf | result = apf.toString()))
}
}
/** A `Content` tagged with the type of a containing object. */ /** A `Content` tagged with the type of a containing object. */
class TypedContent extends MkTypedContent { class TypedContent extends MkTypedContent {
private Content c; private Content c;
@ -1385,7 +1482,7 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract DataFlowType getType(); abstract DataFlowType getType();
abstract boolean toBoolNonEmpty(); abstract ApproxAccessPathFront toApprox();
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
} }
@ -1399,7 +1496,7 @@ class AccessPathFrontNil extends AccessPathFront, TFrontNil {
override DataFlowType getType() { result = t } override DataFlowType getType() { result = t }
override boolean toBoolNonEmpty() { result = false } override ApproxAccessPathFront toApprox() { result = TApproxFrontNil(t) }
} }
class AccessPathFrontHead extends AccessPathFront, TFrontHead { class AccessPathFrontHead extends AccessPathFront, TFrontHead {
@ -1411,7 +1508,7 @@ class AccessPathFrontHead extends AccessPathFront, TFrontHead {
override DataFlowType getType() { result = tc.getContainerType() } override DataFlowType getType() { result = tc.getContainerType() }
override boolean toBoolNonEmpty() { result = true } override ApproxAccessPathFront toApprox() { result.getAHead() = tc }
} }
/** An optional access path front. */ /** An optional access path front. */

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

@ -260,4 +260,9 @@ module Consistency {
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions." msg = "Parameter node with multiple positions."
} }
query predicate uniqueContentApprox(Content c, string msg) {
not exists(unique(ContentApprox approx | approx = getContentApprox(c))) and
msg = "Non-unique content approximation."
}
} }

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

@ -621,23 +621,6 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
) )
} }
/**
* Holds if flow from a parameter at position `pos` inside `c` to a return node of
* kind `kind` is allowed.
*
* We don't expect a parameter to return stored in itself, unless
* explicitly allowed
*/
bindingset[c, pos, kind]
private predicate parameterFlowThroughAllowed(
DataFlowCallable c, ParameterPosition pos, ReturnKindExt kind
) {
exists(ParamNodeEx p |
p.isParameterOf(c, pos) and
parameterFlowThroughAllowed(p, kind)
)
}
private module Stage1 implements StageSig { private module Stage1 implements StageSig {
class Ap = Unit; class Ap = Unit;
@ -980,6 +963,12 @@ private module Stage1 implements StageSig {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, config) and
exists(ap)
}
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) { predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config) {
revFlow(node, _, pragma[only_bind_into](config)) and revFlow(node, _, pragma[only_bind_into](config)) and
@ -1022,9 +1011,13 @@ private module Stage1 implements StageSig {
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
throughFlowNodeCand(ret, config) and throughFlowNodeCand(ret, config) and
kind = ret.getKind() kind = ret.getKind() and
exists(argAp) and
exists(ap)
} }
pragma[nomagic] pragma[nomagic]
@ -1189,6 +1182,8 @@ private signature module StageSig {
predicate revFlow(NodeEx node, Configuration config); predicate revFlow(NodeEx node, Configuration config);
predicate revFlowAp(NodeEx node, Ap ap, Configuration config);
bindingset[node, state, config] bindingset[node, state, config]
predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config); predicate revFlow(NodeEx node, FlowState state, Ap ap, Configuration config);
@ -1196,7 +1191,9 @@ private signature module StageSig {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config); predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config);
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config); predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
);
predicate storeStepCand( predicate storeStepCand(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
@ -1281,21 +1278,43 @@ private module MkStage<StageSig PrevStage> {
import Param import Param
/* Begin: Stage logic. */ /* Begin: Stage logic. */
bindingset[result, apa] // use an alias as a workaround for bad functionality-induced joins
private ApApprox unbindApa(ApApprox apa) { pragma[nomagic]
pragma[only_bind_out](apa) = pragma[only_bind_out](result) private predicate revFlowApAlias(NodeEx node, ApApprox apa, Configuration config) {
PrevStage::revFlowAp(node, apa, config)
}
pragma[nomagic]
private predicate flowIntoCallApa(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, ApApprox apa,
Configuration config
) {
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
PrevStage::revFlowAp(p, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(arg, pragma[only_bind_into](apa), pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate flowOutOfCallApa(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
ApApprox apa, Configuration config
) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and
PrevStage::revFlowAp(out, pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
revFlowApAlias(ret, pragma[only_bind_into](apa), pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughOutOfCall( private predicate flowThroughOutOfCall(
DataFlowCall call, DataFlowCallable c, CcCall ccc, RetNodeEx ret, ReturnKindExt kind, DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
NodeEx out, boolean allowsFieldFlow, Configuration config ApApprox argApa, ApApprox apa, Configuration config
) { ) {
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, pragma[only_bind_into](config)) and exists(ReturnKindExt kind |
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, pragma[only_bind_into](config)) and
PrevStage::returnMayFlowThrough(ret, kind, pragma[only_bind_into](config)) and PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
matchesCall(ccc, call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config)) and
c = ret.getEnclosingCallable() matchesCall(ccc, call)
)
} }
/** /**
@ -1307,39 +1326,50 @@ private module MkStage<StageSig PrevStage> {
* corresponding parameter position and access path of that argument, respectively. * corresponding parameter position and access path of that argument, respectively.
*/ */
pragma[nomagic] pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
filter(node, state, ap, config)
}
pragma[inline]
additional predicate fwdFlow( additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, config) and fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
PrevStage::revFlow(node, state, unbindApa(getApprox(ap)), config) and
filter(node, state, ap, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlow0( private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp, NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config Ap ap, ApApprox apa, Configuration config
) { ) {
sourceNode(node, state, config) and sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and (if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and argAp = apNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
or or
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc | exists(NodeEx mid, FlowState state0, Ap ap0, ApApprox apa0, LocalCc localCc |
fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, config) and fwdFlow(mid, state0, cc, summaryCtx, argAp, ap0, apa0, config) and
localCc = getLocalCc(mid, cc) localCc = getLocalCc(mid, cc)
| |
localStep(mid, state0, node, state, true, _, config, localCc) and localStep(mid, state0, node, state, true, _, config, localCc) and
ap = ap0 ap = ap0 and
apa = apa0
or or
localStep(mid, state0, node, state, false, ap, config, localCc) and localStep(mid, state0, node, state, false, ap, config, localCc) and
ap0 instanceof ApNil ap0 instanceof ApNil and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid | exists(NodeEx mid |
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, pragma[only_bind_into](config)) and fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and jumpStep(mid, node, config) and
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
@ -1352,7 +1382,8 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
exists(NodeEx mid, FlowState state0, ApNil nil | exists(NodeEx mid, FlowState state0, ApNil nil |
@ -1361,32 +1392,32 @@ private module MkStage<StageSig PrevStage> {
cc = ccNone() and cc = ccNone() and
summaryCtx = TParameterPositionNone() and summaryCtx = TParameterPositionNone() and
argAp = apNone() and argAp = apNone() and
ap = getApNil(node) ap = getApNil(node) and
apa = getApprox(ap)
) )
or or
// store // store
exists(TypedContent tc, Ap ap0 | exists(TypedContent tc, Ap ap0 |
fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and fwdFlowStore(_, ap0, tc, node, state, cc, summaryCtx, argAp, config) and
ap = apCons(tc, ap0) ap = apCons(tc, ap0) and
apa = getApprox(ap)
) )
or or
// read // read
exists(Ap ap0, Content c | exists(Ap ap0, Content c |
fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and fwdFlowRead(ap0, c, _, node, state, cc, summaryCtx, argAp, config) and
fwdFlowConsCand(ap0, c, ap, config) fwdFlowConsCand(ap0, c, ap, config) and
apa = getApprox(ap)
) )
or or
// flow into a callable // flow into a callable
exists(ApApprox apa | fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
fwdFlowIn(_, node, state, _, cc, _, _, ap, config) and if PrevStage::parameterMayFlowThrough(node, apa, config)
apa = getApprox(ap) and then (
if PrevStage::parameterMayFlowThrough(node, apa, config) summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
then ( argAp = apSome(ap)
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and ) else (
argAp = apSome(ap) summaryCtx = TParameterPositionNone() and argAp = apNone()
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
)
) )
or or
// flow out of a callable // flow out of a callable
@ -1394,8 +1425,8 @@ private module MkStage<StageSig PrevStage> {
DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc, DataFlowCall call, RetNodeEx ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner DataFlowCallable inner
| |
fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, config) and fwdFlow(ret, state, innercc, summaryCtx, argAp, ap, apa, config) and
flowOutOfCall(call, ret, _, node, allowsFieldFlow, config) and flowOutOfCallApa(call, ret, _, node, allowsFieldFlow, apa, config) and
inner = ret.getEnclosingCallable() and inner = ret.getEnclosingCallable() and
cc = getCallContextReturn(inner, call, innercc) and cc = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
@ -1403,7 +1434,7 @@ private module MkStage<StageSig PrevStage> {
or or
// flow through a callable // flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 | exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, config) and fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config) fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
) )
} }
@ -1413,9 +1444,9 @@ private module MkStage<StageSig PrevStage> {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc, NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
exists(DataFlowType contentType | exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, config) and fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and PrevStage::storeStepCand(node1, apa1, tc, node2, contentType, config) and
typecheckStore(ap1, contentType) typecheckStore(ap1, contentType)
) )
} }
@ -1433,43 +1464,104 @@ private module MkStage<StageSig PrevStage> {
) )
} }
private class ApNonNil instanceof Ap {
pragma[nomagic]
ApNonNil() { not this instanceof ApNil }
string toString() { result = "" }
}
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowRead( private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc, Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
) { ) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and PrevStage::readStepCand(node1, c, node2, config) and
getHeadContent(ap) = c getHeadContent(ap) = c
} }
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, Cc innercc, DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, Configuration config ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) { ) {
exists(ArgNodeEx arg, boolean allowsFieldFlow | exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, config) and fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
}
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowOutFromArg( private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap, DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
Configuration config ApApprox apa, Configuration config
) { ) {
exists( exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
DataFlowCallable c, RetNodeEx ret, ReturnKindExt kind, boolean allowsFieldFlow, CcCall ccc fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
| summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
fwdFlow(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, config) and
flowThroughOutOfCall(call, pragma[only_bind_into](c), ccc, ret, kind, out, allowsFieldFlow,
config) and config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
parameterFlowThroughAllowed(c, pragma[only_bind_into](summaryCtx), kind) (if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
@ -1483,8 +1575,7 @@ private module MkStage<StageSig PrevStage> {
ParameterPosition pos, Ap ap, Configuration config ParameterPosition pos, Ap ap, Configuration config
) { ) {
exists(ParamNodeEx param | exists(ParamNodeEx param |
fwdFlowIn(call, param, _, cc, _, summaryCtx, argAp, ap, config) and fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
PrevStage::parameterMayFlowThrough(param, unbindApa(getApprox(ap)), config) and
pos = param.getPosition() pos = param.getPosition()
) )
} }
@ -1505,41 +1596,55 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config) fwdFlowConsCand(ap1, c, ap2, config)
} }
pragma[nomagic]
private predicate returnFlowsThrough0(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, DataFlowCallable c,
ParameterPosition ppos, Ap argAp, Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow |
fwdFlow(ret, state, ccc, TParameterPositionSome(ppos), apSome(argAp), ap, config) and
flowThroughOutOfCall(_, c, _, pragma[only_bind_into](ret), kind, _, allowsFieldFlow,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic] pragma[nomagic]
private predicate returnFlowsThrough( private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp, RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config Ap ap, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition ppos | exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
returnFlowsThrough0(ret, kind, state, ccc, c, ppos, argAp, ap, config) and fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
p.isParameterOf(c, ppos) and argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
parameterFlowThroughAllowed(p, kind) kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate flowThroughIntoCall( private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Configuration config DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) { ) {
exists(Ap argAp | exists(ApApprox argApa |
flowIntoCall(call, pragma[only_bind_into](arg), pragma[only_bind_into](p), allowsFieldFlow, flowIntoCallApa(call, pragma[only_bind_into](arg), pragma[only_bind_into](p),
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _, returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
pragma[only_bind_into](config)) pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowIntoCallAp(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap ap,
Configuration config
) {
exists(ApApprox apa |
flowIntoCallApa(call, arg, p, allowsFieldFlow, apa, config) and
fwdFlow(arg, _, _, _, _, ap, apa, config)
)
}
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
) )
} }
@ -1628,7 +1733,7 @@ private module MkStage<StageSig PrevStage> {
// flow into a callable // flow into a callable
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and revFlow(p, state, TReturnCtxNone(), returnAp, ap, config) and
flowIntoCall(_, node, p, allowsFieldFlow, config) and flowIntoCallAp(_, node, p, allowsFieldFlow, ap, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and (if allowsFieldFlow = false then ap instanceof ApNil else any()) and
returnCtx = TReturnCtxNone() returnCtx = TReturnCtxNone()
) )
@ -1682,22 +1787,41 @@ private module MkStage<StageSig PrevStage> {
) { ) {
exists(NodeEx out, boolean allowsFieldFlow | exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCall(call, ret, kind, out, allowsFieldFlow, config) and flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any() if allowsFieldFlow = false then ap instanceof ApNil else any()
) )
} }
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
}
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ParamNodeEx p, boolean allowsFieldFlow | exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(pragma[only_bind_into](p), state, revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
TReturnCtxMaybeFlowThrough(pragma[only_bind_into](kind)), apSome(returnAp), ap, config) and revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any()) and
parameterFlowThroughAllowed(p, kind)
) )
} }
@ -1750,6 +1874,11 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) } predicate revFlow(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
pragma[nomagic]
predicate revFlowAp(NodeEx node, Ap ap, Configuration config) {
revFlow(node, _, _, _, ap, config)
}
// use an alias as a workaround for bad functionality-induced joins // use an alias as a workaround for bad functionality-induced joins
pragma[nomagic] pragma[nomagic]
additional predicate revFlowAlias(NodeEx node, Configuration config) { additional predicate revFlowAlias(NodeEx node, Configuration config) {
@ -1786,9 +1915,9 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic] pragma[nomagic]
private predicate parameterFlowsThroughRev( private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Configuration config ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
) { ) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(_), ap, config) and revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind) parameterFlowThroughAllowed(p, kind)
} }
@ -1796,27 +1925,36 @@ private module MkStage<StageSig PrevStage> {
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind | exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, config) parameterFlowsThroughRev(p, ap, kind, _, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate returnMayFlowThrough(RetNodeEx ret, ReturnKindExt kind, Configuration config) { predicate returnMayFlowThrough(
exists(ParamNodeEx p, Ap ap | RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and ) {
parameterFlowsThroughRev(p, ap, kind, config) exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
pragma[nomagic] pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) { predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists( exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
ReturnKindExt returnKind0, Ap returnAp0, ArgNodeEx arg, FlowState state,
ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
revFlow(arg, state, returnCtx, returnAp, ap, config) and revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
) )
} }
@ -2179,16 +2317,16 @@ private module LocalFlowBigStep {
pragma[nomagic] pragma[nomagic]
predicate localFlowBigStep( predicate localFlowBigStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext DataFlowType t, Configuration config, LocalCallContext callContext
) { ) {
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and localFlowStepPlus(node1, state1, node2, preservesValue, t, config, callContext) and
localFlowExit(node2, state1, config) and localFlowExit(node2, state1, config) and
state1 = state2 state1 = state2
or or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and state1 != state2 and
preservesValue = false and preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and t = node2.getDataFlowType() and
callContext.relevantFor(node1.getEnclosingCallable()) and callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() | not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or isUnreachableInCallCached(node1.asNode(), call) or
@ -2202,11 +2340,87 @@ private import LocalFlowBigStep
private module Stage3Param implements MkStage<Stage2>::StageParam { private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2; private module PrevStage = Stage2;
class Ap = ApproxAccessPathFront;
class ApNil = ApproxAccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TApproxFrontNil(node.getDataFlowType())
}
bindingset[tc, tail]
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
pragma[noinline]
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
class ApOption = ApproxAccessPathFrontOption;
ApOption apNone() { result = TApproxAccessPathFrontNone() }
ApOption apSome(Ap ap) { result = TApproxAccessPathFrontSome(ap) }
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApproxAccessPathFrontNil ap, Configuration config, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
exists(lcc)
}
predicate flowOutOfCall = flowOutOfCallNodeCand2/6;
predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) {
exists(Content c |
PrevStage::revFlow(node, pragma[only_bind_into](config)) and
PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and
expectsContentEx(node, c) and
c = ap.getAHead().getContent()
)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
bindingset[node, state, ap, config]
predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and
(
notExpectsContent(node)
or
expectsContentCand(node, ap, config)
)
}
bindingset[ap, contentType]
predicate typecheckStore(Ap ap, DataFlowType contentType) {
// We need to typecheck stores here, since reverse flow through a getter
// might have a different type here compared to inside the getter.
compatibleTypes(ap.getType(), contentType)
}
}
private module Stage3 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param>
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
class Ap = AccessPathFront; class Ap = AccessPathFront;
class ApNil = AccessPathFrontNil; class ApNil = AccessPathFrontNil;
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType()) PrevStage::revFlow(node, _) and result = TFrontNil(node.getDataFlowType())
@ -2226,16 +2440,42 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
import BooleanCallContext import BooleanCallContext
pragma[nomagic]
predicate localStep( predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap, config, _) and exists(lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config)) and
exists(lcc)
} }
predicate flowOutOfCall = flowOutOfCallNodeCand2/6; pragma[nomagic]
predicate flowOutOfCall(
DataFlowCall call, RetNodeEx node1, ReturnKindExt kind, NodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowOutOfCallNodeCand2(call, node1, kind, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
predicate flowIntoCall = flowIntoCallNodeCand2/5; pragma[nomagic]
predicate flowIntoCall(
DataFlowCall call, ArgNodeEx node1, ParamNodeEx node2, boolean allowsFieldFlow,
Configuration config
) {
exists(FlowState state |
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, pragma[only_bind_into](state), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node1, pragma[only_bind_into](state), _,
pragma[only_bind_into](config))
)
}
pragma[nomagic] pragma[nomagic]
private predicate clearSet(NodeEx node, ContentSet c, Configuration config) { private predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
@ -2291,8 +2531,8 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
} }
} }
private module Stage3 implements StageSig { private module Stage4 implements StageSig {
import MkStage<Stage2>::Stage<Stage3Param> import MkStage<Stage3>::Stage<Stage4Param>
} }
/** /**
@ -2303,8 +2543,8 @@ private predicate flowCandSummaryCtx(
NodeEx node, FlowState state, AccessPathFront argApf, Configuration config NodeEx node, FlowState state, AccessPathFront argApf, Configuration config
) { ) {
exists(AccessPathFront apf | exists(AccessPathFront apf |
Stage3::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf, config) and
Stage3::fwdFlow(node, state, any(Stage3::CcCall ccc), _, TAccessPathFrontSome(argApf), apf, Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, TAccessPathFrontSome(argApf), apf,
config) config)
) )
} }
@ -2315,10 +2555,10 @@ private predicate flowCandSummaryCtx(
*/ */
private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) { private predicate expensiveLen2unfolding(TypedContent tc, Configuration config) {
exists(int tails, int nodes, int apLimit, int tupleLimit | exists(int tails, int nodes, int apLimit, int tupleLimit |
tails = strictcount(AccessPathFront apf | Stage3::consCand(tc, apf, config)) and tails = strictcount(AccessPathFront apf | Stage4::consCand(tc, apf, config)) and
nodes = nodes =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage3::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) Stage4::revFlow(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
or or
flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config) flowCandSummaryCtx(n, state, any(AccessPathFrontHead apf | apf.getHead() = tc), config)
) and ) and
@ -2332,11 +2572,11 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
private newtype TAccessPathApprox = private newtype TAccessPathApprox =
TNil(DataFlowType t) or TNil(DataFlowType t) or
TConsNil(TypedContent tc, DataFlowType t) { TConsNil(TypedContent tc, DataFlowType t) {
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
not expensiveLen2unfolding(tc, _) not expensiveLen2unfolding(tc, _)
} or } or
TConsCons(TypedContent tc1, TypedContent tc2, int len) { TConsCons(TypedContent tc1, TypedContent tc2, int len) {
Stage3::consCand(tc1, TFrontHead(tc2), _) and Stage4::consCand(tc1, TFrontHead(tc2), _) and
len in [2 .. accessPathLimit()] and len in [2 .. accessPathLimit()] and
not expensiveLen2unfolding(tc1, _) not expensiveLen2unfolding(tc1, _)
} or } or
@ -2466,7 +2706,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
override AccessPathApprox pop(TypedContent head) { override AccessPathApprox pop(TypedContent head) {
head = tc and head = tc and
( (
exists(TypedContent tc2 | Stage3::consCand(tc, TFrontHead(tc2), _) | exists(TypedContent tc2 | Stage4::consCand(tc, TFrontHead(tc2), _) |
result = TConsCons(tc2, _, len - 1) result = TConsCons(tc2, _, len - 1)
or or
len = 2 and len = 2 and
@ -2477,7 +2717,7 @@ private class AccessPathApproxCons1 extends AccessPathApproxCons, TCons1 {
or or
exists(DataFlowType t | exists(DataFlowType t |
len = 1 and len = 1 and
Stage3::consCand(tc, TFrontNil(t), _) and Stage4::consCand(tc, TFrontNil(t), _) and
result = TNil(t) result = TNil(t)
) )
) )
@ -2502,13 +2742,14 @@ private class AccessPathApproxOption extends TAccessPathApproxOption {
} }
} }
private module Stage4Param implements MkStage<Stage3>::StageParam { private module Stage5Param implements MkStage<Stage4>::StageParam {
private module PrevStage = Stage3; private module PrevStage = Stage4;
class Ap = AccessPathApprox; class Ap = AccessPathApprox;
class ApNil = AccessPathApproxNil; class ApNil = AccessPathApproxNil;
pragma[nomagic]
PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() }
ApNil getApNil(NodeEx node) { ApNil getApNil(NodeEx node) {
@ -2534,7 +2775,9 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
ApNil ap, Configuration config, LocalCc lcc ApNil ap, Configuration config, LocalCc lcc
) { ) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getFront(), config, lcc) localFlowBigStep(node1, state1, node2, state2, preservesValue, ap.getType(), config, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _, pragma[only_bind_into](config)) and
PrevStage::revFlowAlias(node2, pragma[only_bind_into](state2), _, pragma[only_bind_into](config))
} }
pragma[nomagic] pragma[nomagic]
@ -2571,7 +2814,7 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
predicate typecheckStore(Ap ap, DataFlowType contentType) { any() } predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
} }
private module Stage4 = MkStage<Stage3>::Stage<Stage4Param>; private module Stage5 = MkStage<Stage4>::Stage<Stage5Param>;
bindingset[conf, result] bindingset[conf, result]
private Configuration unbindConf(Configuration conf) { private Configuration unbindConf(Configuration conf) {
@ -2585,8 +2828,8 @@ private predicate nodeMayUseSummary0(
) { ) {
exists(AccessPathApprox apa0 | exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and c = n.getEnclosingCallable() and
Stage4::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage4::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos), Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
TAccessPathApproxSome(apa), apa0, config) TAccessPathApproxSome(apa), apa0, config)
) )
} }
@ -2596,7 +2839,7 @@ private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) { ) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p | exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
Stage4::parameterMayFlowThrough(p, apa, config) and Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos) p.isParameterOf(c, pos)
) )
@ -2606,8 +2849,8 @@ private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) { TSummaryCtxSome(ParamNodeEx p, FlowState state, AccessPath ap) {
exists(Configuration config | exists(Configuration config |
Stage4::parameterMayFlowThrough(p, ap.getApprox(), config) and Stage5::parameterMayFlowThrough(p, ap.getApprox(), config) and
Stage4::revFlow(p, state, _, config) Stage5::revFlow(p, state, _, config)
) )
} }
@ -2656,7 +2899,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
len = apa.len() and len = apa.len() and
result = result =
strictcount(AccessPathFront apf | strictcount(AccessPathFront apf |
Stage4::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1), Stage5::consCand(tc, any(AccessPathApprox ap | ap.getFront() = apf and ap.len() = len - 1),
config) config)
) )
) )
@ -2665,7 +2908,7 @@ private int count1to2unfold(AccessPathApproxCons1 apa, Configuration config) {
private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) { private int countNodesUsingAccessPath(AccessPathApprox apa, Configuration config) {
result = result =
strictcount(NodeEx n, FlowState state | strictcount(NodeEx n, FlowState state |
Stage4::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config) Stage5::revFlow(n, state, apa, config) or nodeMayUseSummary(n, state, apa, config)
) )
} }
@ -2686,7 +2929,7 @@ private predicate expensiveLen1to2unfolding(AccessPathApproxCons1 apa, Configura
private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) { private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
exists(TypedContent head | exists(TypedContent head |
apa.pop(head) = result and apa.pop(head) = result and
Stage4::consCand(head, result, config) Stage5::consCand(head, result, config)
) )
} }
@ -2768,7 +3011,7 @@ private newtype TPathNode =
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
) { ) {
// A PathNode is introduced by a source ... // A PathNode is introduced by a source ...
Stage4::revFlow(node, state, config) and Stage5::revFlow(node, state, config) and
sourceNode(node, state, config) and sourceNode(node, state, config) and
( (
if hasSourceCallCtx(config) if hasSourceCallCtx(config)
@ -2782,7 +3025,7 @@ private newtype TPathNode =
exists(PathNodeMid mid | exists(PathNodeMid mid |
pathStep(mid, node, state, cc, sc, ap) and pathStep(mid, node, state, cc, sc, ap) and
pragma[only_bind_into](config) = mid.getConfiguration() and pragma[only_bind_into](config) = mid.getConfiguration() and
Stage4::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config)) Stage5::revFlow(node, state, ap.getApprox(), pragma[only_bind_into](config))
) )
} or } or
TPathNodeSink(NodeEx node, FlowState state, Configuration config) { TPathNodeSink(NodeEx node, FlowState state, Configuration config) {
@ -2924,7 +3167,7 @@ private class AccessPathCons2 extends AccessPath, TAccessPathCons2 {
override TypedContent getHead() { result = head1 } override TypedContent getHead() { result = head1 }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head1, result.getApprox(), _) and Stage5::consCand(head1, result.getApprox(), _) and
result.getHead() = head2 and result.getHead() = head2 and
result.length() = len - 1 result.length() = len - 1
} }
@ -2955,7 +3198,7 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
override TypedContent getHead() { result = head } override TypedContent getHead() { result = head }
override AccessPath getTail() { override AccessPath getTail() {
Stage4::consCand(head, result.getApprox(), _) and result.length() = len - 1 Stage5::consCand(head, result.getApprox(), _) and result.length() = len - 1
} }
override AccessPathFrontHead getFront() { result = TFrontHead(head) } override AccessPathFrontHead getFront() { result = TFrontHead(head) }
@ -3347,7 +3590,8 @@ private predicate pathStep(
AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC AccessPath ap0, NodeEx midnode, FlowState state0, Configuration conf, LocalCallContext localCC
| |
pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and pathNode(mid, midnode, state0, cc, sc, ap0, conf, localCC) and
localFlowBigStep(midnode, state0, node, state, false, ap.getFront(), conf, localCC) and localFlowBigStep(midnode, state0, node, state, false, ap.(AccessPathNil).getType(), conf,
localCC) and
ap0 instanceof AccessPathNil ap0 instanceof AccessPathNil
) )
or or
@ -3389,7 +3633,7 @@ private predicate pathReadStep(
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
tc = ap0.getHead() and tc = ap0.getHead() and
Stage4::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and Stage5::readStepCand(mid.getNodeEx(), tc.getContent(), node, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3399,7 +3643,7 @@ private predicate pathStoreStep(
PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc PathNodeMid mid, NodeEx node, FlowState state, AccessPath ap0, TypedContent tc, CallContext cc
) { ) {
ap0 = mid.getAp() and ap0 = mid.getAp() and
Stage4::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and Stage5::storeStepCand(mid.getNodeEx(), _, tc, node, _, mid.getConfiguration()) and
state = mid.getState() and state = mid.getState() and
cc = mid.getCallContext() cc = mid.getCallContext()
} }
@ -3436,7 +3680,7 @@ private NodeEx getAnOutNodeFlow(
ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config ReturnKindExt kind, DataFlowCall call, AccessPathApprox apa, Configuration config
) { ) {
result.asNode() = kind.getAnOutNode(call) and result.asNode() = kind.getAnOutNode(call) and
Stage4::revFlow(result, _, apa, config) Stage5::revFlow(result, _, apa, config)
} }
/** /**
@ -3472,7 +3716,7 @@ private predicate parameterCand(
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
) { ) {
exists(ParamNodeEx p | exists(ParamNodeEx p |
Stage4::revFlow(p, _, apa, config) and Stage5::revFlow(p, _, apa, config) and
p.isParameterOf(callable, pos) p.isParameterOf(callable, pos)
) )
} }
@ -3751,9 +3995,17 @@ predicate stageStats(
n = 45 and n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, config) Stage4::stats(false, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Fwd" and n = 50 and finalStats(true, nodes, fields, conscand, states, tuples) stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, config)
or or
stage = "5 Rev" and n = 55 and finalStats(false, nodes, fields, conscand, states, tuples) stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, config)
or
stage = "6 Fwd" and n = 60 and finalStats(true, nodes, fields, conscand, states, tuples)
or
stage = "6 Rev" and n = 65 and finalStats(false, nodes, fields, conscand, states, tuples)
} }
private module FlowExploration { private module FlowExploration {

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

@ -904,6 +904,13 @@ private module Cached {
TElementContent() or TElementContent() or
TSyntheticFieldContent(SyntheticField f) TSyntheticFieldContent(SyntheticField f)
cached
newtype TContentApprox =
TFieldApproxContent(string firstChar) { firstChar = approximateFieldContent(_) } or
TPropertyApproxContent(string firstChar) { firstChar = approximatePropertyContent(_) } or
TElementApproxContent() or
TSyntheticFieldApproxContent()
pragma[nomagic] pragma[nomagic]
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) { private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
not t1 instanceof Gvn::TypeParameterGvnType and not t1 instanceof Gvn::TypeParameterGvnType and
@ -2246,6 +2253,46 @@ predicate allowParameterReturnInSelf(ParameterNode p) {
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p) FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
} }
/** An approximated `Content`. */
class ContentApprox extends TContentApprox {
/** Gets a textual representation of this approximated `Content`. */
string toString() {
exists(string firstChar |
this = TFieldApproxContent(firstChar) and result = "approximated field " + firstChar
)
or
exists(string firstChar |
this = TPropertyApproxContent(firstChar) and result = "approximated property " + firstChar
)
or
this = TElementApproxContent() and result = "element"
or
this = TSyntheticFieldApproxContent() and result = "approximated synthetic field"
}
}
/** Gets a string for approximating the name of a field. */
private string approximateFieldContent(FieldContent fc) {
result = fc.getField().getName().prefix(1)
}
/** Gets a string for approximating the name of a property. */
private string approximatePropertyContent(PropertyContent pc) {
result = pc.getProperty().getName().prefix(1)
}
/** Gets an approximated value for content `c`. */
pragma[nomagic]
ContentApprox getContentApprox(Content c) {
result = TFieldApproxContent(approximateFieldContent(c))
or
result = TPropertyApproxContent(approximatePropertyContent(c))
or
c instanceof ElementContent and result = TElementApproxContent()
or
c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent()
}
/** /**
* A module importing the modules that provide synthetic field declarations, * A module importing the modules that provide synthetic field declarations,
* ensuring that they are visible to the taint tracking / data flow library. * ensuring that they are visible to the taint tracking / data flow library.

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

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

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

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

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

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

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

@ -36,9 +36,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
} }
/** A source of remote user input. */ /** A source of remote user input. */
class RemoteSource extends Source { class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* A sink in `System.Diagnostic.Process` or its related classes. * A sink in `System.Diagnostic.Process` or its related classes.

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

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

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

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

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

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

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

@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
} }
/** A source of remote user input. */ /** A source of remote user input. */
class RemoteSource extends Source { class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP * An argument that sets the `Path` property of a `DirectoryEntry` object that is a sink for LDAP

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

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

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

@ -43,9 +43,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
} }
/** A source of remote user input. */ /** A source of remote user input. */
class RemoteSource extends Source { class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* The input argument to a call to `XmlReader.Create` where the input will not be validated against * The input argument to a call to `XmlReader.Create` where the input will not be validated against

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

@ -38,9 +38,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
} }
/** A source of remote user input. */ /** A source of remote user input. */
class RemoteSource extends Source { class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* An expression that represents a regular expression with potential exponential behavior. * An expression that represents a regular expression with potential exponential behavior.

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

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

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

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

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

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

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

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

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

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

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

@ -50,9 +50,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
} }
/** A source of remote user input. */ /** A source of remote user input. */
class RemoteSource extends Source { class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a * A URL argument to a call to `HttpResponse.Redirect()` or `Controller.Redirect()`, that is a

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

@ -14,9 +14,7 @@ private import semmle.code.csharp.security.Sanitizers
*/ */
abstract class Source extends DataFlow::Node { } abstract class Source extends DataFlow::Node { }
private class RemoteSource extends Source { private class RemoteSource extends Source instanceof RemoteFlowSource { }
RemoteSource() { this instanceof RemoteFlowSource }
}
/** /**
* A data flow sink for untrusted user input used in XML processing. * A data flow sink for untrusted user input used in XML processing.

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

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

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

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

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

@ -27,9 +27,7 @@ private class ExternalXssSink extends Sink {
ExternalXssSink() { sinkNode(this, "xss") } ExternalXssSink() { sinkNode(this, "xss") }
} }
private class HtmlSinkSink extends Sink { private class HtmlSinkSink extends Sink instanceof HtmlSink {
HtmlSinkSink() { this instanceof HtmlSink }
override string explanation() { override string explanation() {
this instanceof WebPageWriteLiteralSink and this instanceof WebPageWriteLiteralSink and
result = "System.Web.WebPages.WebPage.WriteLiteral() method" result = "System.Web.WebPages.WebPage.WriteLiteral() method"

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

@ -12,6 +12,7 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls
private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.WCF
private import semmle.code.csharp.frameworks.microsoft.Owin private import semmle.code.csharp.frameworks.microsoft.Owin
private import semmle.code.csharp.frameworks.microsoft.AspNetCore private import semmle.code.csharp.frameworks.microsoft.AspNetCore
private import semmle.code.csharp.dataflow.ExternalFlow
/** A data flow source of remote user input. */ /** A data flow source of remote user input. */
abstract class RemoteFlowSource extends DataFlow::Node { abstract class RemoteFlowSource extends DataFlow::Node {
@ -261,3 +262,9 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" } override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
} }
private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
override string getSourceType() { result = "external" }
}

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

@ -44,9 +44,7 @@ class SuppressionComment extends CommentLine {
/** /**
* The scope of an alert suppression comment. * The scope of an alert suppression comment.
*/ */
class SuppressionScope extends @commentline { class SuppressionScope extends @commentline instanceof SuppressionComment {
SuppressionScope() { this instanceof SuppressionComment }
/** Gets a suppression comment with this scope. */ /** Gets a suppression comment with this scope. */
SuppressionComment getSuppressionComment() { result = this } SuppressionComment getSuppressionComment() { result = this }
@ -60,7 +58,7 @@ class SuppressionScope extends @commentline {
predicate hasLocationInfo( predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn string filepath, int startline, int startcolumn, int endline, int endcolumn
) { ) {
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn) super.covers(filepath, startline, startcolumn, endline, endcolumn)
} }
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */

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

@ -24,6 +24,12 @@ class TestLibrary extends RefType {
} }
} }
/** Holds if the given callable is not worth supporting. */
private predicate isUninteresting(DotNet::Callable c) {
c.getDeclaringType() instanceof TestLibrary or
c.(Constructor).isParameterless()
}
/** /**
* An external API from either the C# Standard Library or a 3rd party library. * An external API from either the C# Standard Library or a 3rd party library.
*/ */
@ -31,7 +37,8 @@ class ExternalApi extends DotNet::Callable {
ExternalApi() { ExternalApi() {
this.isUnboundDeclaration() and this.isUnboundDeclaration() and
this.fromLibrary() and this.fromLibrary() and
this.(Modifiable).isEffectivelyPublic() this.(Modifiable).isEffectivelyPublic() and
not isUninteresting(this)
} }
/** /**
@ -84,17 +91,6 @@ class ExternalApi extends DotNet::Callable {
defaultAdditionalTaintStep(this.getAnInput(), _) defaultAdditionalTaintStep(this.getAnInput(), _)
} }
/** Holds if this API is a constructor without parameters. */
private predicate isParameterlessConstructor() {
this instanceof Constructor and this.getNumberOfParameters() = 0
}
/** Holds if this API is part of a common testing library or framework. */
private predicate isTestLibrary() { this.getDeclaringType() instanceof TestLibrary }
/** Holds if this API is not worth supporting. */
predicate isUninteresting() { this.isTestLibrary() or this.isParameterlessConstructor() }
/** Holds if this API is a known source. */ /** Holds if this API is a known source. */
predicate isSource() { predicate isSource() {
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _) this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)

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

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

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

@ -12,11 +12,8 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
private import ExternalApi private import ExternalApi
private predicate relevant(ExternalApi api) { private predicate relevant(ExternalApi api) {
not api.isUninteresting() and api.isSupported() or
( api instanceof FlowSummaryImpl::Public::NeutralCallable
api.isSupported() or
api instanceof FlowSummaryImpl::Public::NeutralCallable
)
} }
from string info, int usages from string info, int usages

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

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

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

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

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

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

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

@ -12,7 +12,6 @@ private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSumma
private import ExternalApi private import ExternalApi
private predicate relevant(ExternalApi api) { private predicate relevant(ExternalApi api) {
not api.isUninteresting() and
not api.isSupported() and not api.isSupported() and
not api instanceof FlowSummaryImpl::Public::NeutralCallable not api instanceof FlowSummaryImpl::Public::NeutralCallable
} }

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

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

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

@ -58,9 +58,7 @@ module RequestForgery {
* A remote data flow source taken as a source * A remote data flow source taken as a source
* for Server Side Request Forgery(SSRF) Vulnerabilities. * for Server Side Request Forgery(SSRF) Vulnerabilities.
*/ */
private class RemoteFlowSourceAsSource extends Source { private class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { }
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/** /**
* An url argument to a `HttpRequestMessage` constructor call * An url argument to a `HttpRequestMessage` constructor call

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

@ -16,7 +16,6 @@ private import Telemetry.ExternalApi
from Call c, ExternalApi api from Call c, ExternalApi api
where where
c.getTarget().getUnboundDeclaration() = api and c.getTarget().getUnboundDeclaration() = api and
not api.isUninteresting() and
not api.isSupported() and not api.isSupported() and
not api instanceof FlowSummaryImpl::Public::NeutralCallable not api instanceof FlowSummaryImpl::Public::NeutralCallable
select c, "Call to unsupported external API $@.", api, api.toString() select c, "Call to unsupported external API $@.", api, api.toString()

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

@ -38,7 +38,9 @@ private predicate isRelevantForModels(CS::Callable api) {
api.getDeclaringType().getNamespace().getFullName() != "" and api.getDeclaringType().getNamespace().getFullName() != "" and
not api instanceof CS::ConversionOperator and not api instanceof CS::ConversionOperator and
not api instanceof Util::MainMethod and not api instanceof Util::MainMethod and
not api instanceof CS::Destructor not api instanceof CS::Destructor and
not api instanceof CS::AnonymousFunctionExpr and
not api.(CS::Constructor).isParameterless()
} }
/** /**

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

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

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

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

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

@ -6,9 +6,7 @@ private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
IncludeAllSummarizedCallable() { exists(this) } IncludeAllSummarizedCallable() { exists(this) }
} }
private class IncludeNeutralCallable extends RelevantNeutralCallable { private class IncludeNeutralCallable extends RelevantNeutralCallable instanceof FlowSummaryImpl::Public::NeutralCallable {
IncludeNeutralCallable() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */ /** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
final override string getCallableCsv() { result = Csv::asPartialNeutralModel(this) } final override string getCallableCsv() { result = Csv::asPartialNeutralModel(this) }
} }

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

@ -2,9 +2,7 @@ import shared.FlowSummaries
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
private import semmle.code.csharp.dataflow.ExternalFlow private import semmle.code.csharp.dataflow.ExternalFlow
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable { class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable instanceof SummarizedCallable {
IncludeFilteredSummarizedCallable() { this instanceof SummarizedCallable }
/** /**
* Holds if flow is propagated between `input` and `output` and * Holds if flow is propagated between `input` and `output` and
* if there is no summary for a callable in a `base` class or interface * if there is no summary for a callable in a `base` class or interface
@ -13,7 +11,7 @@ class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
override predicate relevantSummary( override predicate relevantSummary(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) { ) {
this.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and super.propagatesFlow(input, output, preservesValue) and
not exists(IncludeSummarizedCallable rsc | not exists(IncludeSummarizedCallable rsc |
isBaseCallableOrPrototype(rsc) and isBaseCallableOrPrototype(rsc) and
rsc.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and rsc.(SummarizedCallable).propagatesFlow(input, output, preservesValue) and

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

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

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

@ -131,4 +131,15 @@ public class CollectionFlow
{ {
return a; return a;
} }
} }
// A neutral model should not be created for a parameterless constructor.
public class ParameterlessConstructor
{
public bool IsInitialized;
public ParameterlessConstructor()
{
IsInitialized = true;
}
}

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

@ -5,4 +5,4 @@ where
a.getAnOperand() = v.getAnAccess() and a.getAnOperand() = v.getAnAccess() and
cmp.getAnOperand() = a and cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess() cmp.getAnOperand() = v.getAnAccess()
select cmp, "Overflow check." select cmp, "Overflow check."

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

@ -6,4 +6,4 @@ where
cmp.getAnOperand() = a and cmp.getAnOperand() = a and
cmp.getAnOperand() = v.getAnAccess() and cmp.getAnOperand() = v.getAnAccess() and
forall(Expr op | op = a.getAnOperand() | isSmall(op)) forall(Expr op | op = a.getAnOperand() | isSmall(op))
select cmp, "Bad overflow check." select cmp, "Bad overflow check."

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

@ -9,4 +9,4 @@ where
cmp.getAnOperand() = v.getAnAccess() and cmp.getAnOperand() = v.getAnAccess() and
forall(Expr op | op = a.getAnOperand() | isSmall(op)) and forall(Expr op | op = a.getAnOperand() | isSmall(op)) and
not isSmall(a.getExplicitlyConverted()) not isSmall(a.getExplicitlyConverted())
select cmp, "Bad overflow check" select cmp, "Bad overflow check"

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

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

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

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

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