Merge remote-tracking branch 'upstream/main' into 'rc/3.14'

This commit is contained in:
Arthur Baars
2024-06-28 19:50:35 +02:00
772 changed files with 16846 additions and 17035 deletions

View File

@@ -142,7 +142,6 @@ signature module InputSig<LocationSig Location> {
* steps, then it will check that the types of `n1` and `n2` are compatible.
* If they are not, then flow will be blocked.
*/
bindingset[t1, t2]
predicate compatibleTypes(DataFlowType t1, DataFlowType t2);
/**

View File

@@ -645,6 +645,8 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
Location getLocation() {
exists(CapturedVariable v | this = TVariable(v) and result = v.getLocation())
or
exists(Callable c | this = TThis(c) and result = c.getLocation())
}
}

View File

@@ -1444,6 +1444,31 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
)
}
pragma[nomagic]
private predicate compatibleContainer0(ApHeadContent apc, DataFlowType containerType) {
exists(DataFlowType containerType0, Content c |
PrevStage::storeStepCand(_, _, c, _, _, containerType0) and
not isTopType(containerType0) and
compatibleTypesCached(containerType0, containerType) and
apc = projectToHeadContent(c)
)
}
pragma[nomagic]
private predicate topTypeContent(ApHeadContent apc) {
exists(DataFlowType containerType0, Content c |
PrevStage::storeStepCand(_, _, c, _, _, containerType0) and
isTopType(containerType0) and
apc = projectToHeadContent(c)
)
}
bindingset[apc, containerType]
pragma[inline_late]
private predicate compatibleContainer(ApHeadContent apc, DataFlowType containerType) {
compatibleContainer0(apc, containerType)
}
/**
* Holds if `node` is reachable with access path `ap` from a source.
*
@@ -1465,7 +1490,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
PrevStage::revFlow(node, state, apa) and
filter(node, state, t0, ap, t)
filter(node, state, t0, ap, t) and
(
if castingNodeEx(node)
then
ap instanceof ApNil or
compatibleContainer(getHeadContent(ap), node.getDataFlowType()) or
topTypeContent(getHeadContent(ap))
else any()
)
}
pragma[nomagic]
@@ -1776,22 +1809,20 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
pragma[inline]
predicate fwdFlowIn(
DataFlowCall call, DataFlowCallable inner, ParamNodeEx p, FlowState state, Cc outercc,
CcCall innercc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t,
Ap ap, ApApprox apa, boolean cc, boolean allowsFlowThrough
DataFlowCall call, ArgNodeEx arg, DataFlowCallable inner, ParamNodeEx p,
FlowState state, Cc outercc, CcCall innercc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa, boolean cc, boolean allowsFlowThrough
) {
exists(ArgNodeEx arg |
// type flow disabled: linear recursion
fwdFlowInCandTypeFlowDisabled(call, arg, state, outercc, inner, p, summaryCtx, argT,
argAp, t, ap, apa, cc, allowsFlowThrough) and
fwdFlowInValidEdgeTypeFlowDisabled(call, inner, innercc, pragma[only_bind_into](cc))
or
// type flow enabled: non-linear recursion
exists(boolean emptyAp |
fwdFlowIntoArg(arg, state, outercc, summaryCtx, argT, argAp, t, ap, emptyAp, apa, cc) and
fwdFlowInValidEdgeTypeFlowEnabled(call, arg, outercc, inner, p, innercc, emptyAp,
apa, cc, allowsFlowThrough)
)
// type flow disabled: linear recursion
fwdFlowInCandTypeFlowDisabled(call, arg, state, outercc, inner, p, summaryCtx, argT,
argAp, t, ap, apa, cc, allowsFlowThrough) and
fwdFlowInValidEdgeTypeFlowDisabled(call, inner, innercc, pragma[only_bind_into](cc))
or
// type flow enabled: non-linear recursion
exists(boolean emptyAp |
fwdFlowIntoArg(arg, state, outercc, summaryCtx, argT, argAp, t, ap, emptyAp, apa, cc) and
fwdFlowInValidEdgeTypeFlowEnabled(call, arg, outercc, inner, p, innercc, emptyAp, apa,
cc, allowsFlowThrough)
)
}
}
@@ -1804,8 +1835,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
boolean allowsFlowThrough
) {
exists(boolean allowsFlowThrough0 |
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(_, _, p, state, _, innercc, _, _, _, t, ap,
apa, _, allowsFlowThrough0) and
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(_, _, _, p, state, _, innercc, _, _, _, t,
ap, apa, _, allowsFlowThrough0) and
if PrevStage::parameterMayFlowThrough(p, apa)
then allowsFlowThrough = allowsFlowThrough0
else allowsFlowThrough = false
@@ -1907,8 +1938,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
DataFlowCall call, DataFlowCallable c, ParamNodeEx p, FlowState state, CcCall innercc,
Typ t, Ap ap, boolean cc
) {
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(call, c, p, state, _, innercc, _, _, _, t,
ap, _, cc, _)
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(call, _, c, p, state, _, innercc, _, _, _,
t, ap, _, cc, _)
}
pragma[nomagic]
@@ -1993,13 +2024,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
pragma[inline]
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Typ innerArgT, Ap innerArgAp, ApApprox innerArgApa
DataFlowCall call, ArgNodeEx arg, Cc cc, FlowState state, CcCall ccc,
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa,
RetNodeEx ret, ParamNodeEx innerSummaryCtx, Typ innerArgT, Ap innerArgAp,
ApApprox innerArgApa
) {
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgT, innerArgAp, innerArgApa, t,
ap, apa) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argT, argAp, innerSummaryCtx, innerArgT,
fwdFlowIsEntered(call, arg, cc, ccc, summaryCtx, argT, argAp, innerSummaryCtx, innerArgT,
innerArgAp)
}
@@ -2009,8 +2041,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa, RetNodeEx ret,
ApApprox innerArgApa
) {
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argT, argAp, t, ap, apa, ret, _, _, _,
innerArgApa)
fwdFlowThrough0(call, _, cc, state, ccc, summaryCtx, argT, argAp, t, ap, apa, ret, _, _,
_, innerArgApa)
}
private module FwdFlowThroughRestriction implements FwdFlowInInputSig {
@@ -2025,11 +2057,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, ParamNodeEx p, Typ t, Ap ap
DataFlowCall call, ArgNodeEx arg, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx,
TypOption argT, ApOption argAp, ParamNodeEx p, Typ t, Ap ap
) {
FwdFlowIn<FwdFlowThroughRestriction>::fwdFlowIn(call, _, p, _, cc, innerCc, summaryCtx,
argT, argAp, t, ap, _, _, true)
FwdFlowIn<FwdFlowThroughRestriction>::fwdFlowIn(call, arg, _, p, _, cc, innerCc,
summaryCtx, argT, argAp, t, ap, _, _, true)
}
pragma[nomagic]
@@ -2052,8 +2084,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Typ innerArgT, Ap innerArgAp, ApApprox innerArgApa
) {
fwdFlowThrough0(call, _, state, ccc, _, _, _, _, ap, apa, ret, innerSummaryCtx, innerArgT,
innerArgAp, innerArgApa)
fwdFlowThrough0(call, _, _, state, ccc, _, _, _, _, ap, apa, ret, innerSummaryCtx,
innerArgT, innerArgAp, innerArgApa)
}
pragma[nomagic]
@@ -2487,6 +2519,274 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
callEdgeReturn(call, c, _, _, _, _, _)
}
/**
* INTERNAL: Only for debugging.
*
* Provides a graph representation of the data flow in this stage suitable for use in a `path-problem` query.
*/
additional module Graph {
private newtype TStagePathNode =
TStagePathNodeMid(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap
) {
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _) and
revFlow(node, state, _, _, ap)
} or
TStagePathNodeSrcGrp() or
TStagePathNodeSinkGrp()
class StagePathNode extends TStagePathNode {
abstract string toString();
abstract Location getLocation();
/** Gets the corresponding `Node`, if any. */
Node getNode() { none() }
predicate isSource() { none() }
predicate isSink() { none() }
predicate isArbitrarySource() { this instanceof TStagePathNodeSrcGrp }
predicate isArbitrarySink() { this instanceof TStagePathNodeSinkGrp }
}
class StagePathNodeSrcGrp extends StagePathNode, TStagePathNodeSrcGrp {
override string toString() { result = "<any source>" }
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
}
class StagePathNodeSinkGrp extends StagePathNode, TStagePathNodeSinkGrp {
override string toString() { result = "<any sink>" }
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
}
class StagePathNodeMid extends StagePathNode, TStagePathNodeMid {
NodeEx node;
FlowState state;
Cc cc;
ParamNodeOption summaryCtx;
TypOption argT;
ApOption argAp;
Typ t;
Ap ap;
StagePathNodeMid() {
this = TStagePathNodeMid(node, state, cc, summaryCtx, argT, argAp, t, ap)
}
override string toString() {
result =
node.toString() + " " + cc.toString() + " " + t.toString() + " " + ap.toString()
}
override Location getLocation() { result = node.getLocation() }
override Node getNode() { result = node.asNode() }
override predicate isSource() {
sourceNode(node, state) and
(if hasSourceCallCtx() then cc = ccSomeCall() else cc = ccNone()) and
summaryCtx = TParamNodeNone() and
t = getNodeTyp(node) and
ap instanceof ApNil
}
override predicate isSink() {
sinkNode(node, state) and
(if hasSinkCallCtx() then instanceofCcNoCall(cc) else any()) and
ap instanceof ApNil
}
}
pragma[nomagic]
private predicate fwdFlowInStep(
ArgNodeEx arg, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap,
boolean allowsFlowThrough
) {
exists(ApApprox apa, boolean allowsFlowThrough0 |
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(_, arg, _, p, state, outercc, innercc,
summaryCtx, argT, argAp, t, ap, apa, _, allowsFlowThrough0) and
if PrevStage::parameterMayFlowThrough(p, apa)
then allowsFlowThrough = allowsFlowThrough0
else allowsFlowThrough = false
)
}
pragma[nomagic]
private predicate fwdFlowThroughStep0(
DataFlowCall call, ArgNodeEx arg, Cc cc, FlowState state, CcCall ccc,
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa,
RetNodeEx ret, ParamNodeEx innerSummaryCtx, Typ innerArgT, Ap innerArgAp,
ApApprox innerArgApa
) {
fwdFlowThrough0(call, arg, cc, state, ccc, summaryCtx, argT, argAp, t, ap, apa, ret,
innerSummaryCtx, innerArgT, innerArgAp, innerArgApa)
}
bindingset[node, state, cc, summaryCtx, argT, argAp, t, ap]
pragma[inline_late]
private StagePathNode mkStagePathNode(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap
) {
result = TStagePathNodeMid(node, state, cc, summaryCtx, argT, argAp, t, ap)
}
pragma[nomagic]
private predicate fwdFlowThroughStep1(
StagePathNode pn1, StagePathNode pn2, StagePathNode pn3, DataFlowCall call, Cc cc,
FlowState state, CcCall ccc, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp,
Typ t, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa
) {
exists(FlowState state0, ArgNodeEx arg, ParamNodeEx p, Typ innerArgT, Ap innerArgAp |
fwdFlowThroughStep0(call, arg, cc, state, ccc, summaryCtx, argT, argAp, t, ap, apa,
ret, p, innerArgT, innerArgAp, innerArgApa) and
revFlow(arg, state0, _, _, _) and
pn1 = mkStagePathNode(arg, state0, cc, summaryCtx, argT, argAp, innerArgT, innerArgAp) and
pn2 =
mkStagePathNode(p, state0, ccc, TParamNodeSome(p.asNode()),
TypOption::some(innerArgT), apSome(innerArgAp), innerArgT, innerArgAp) and
pn3 =
mkStagePathNode(ret, state, ccc, TParamNodeSome(p.asNode()),
TypOption::some(innerArgT), apSome(innerArgAp), t, ap)
)
}
pragma[nomagic]
private predicate fwdFlowThroughStep2(
StagePathNode pn1, StagePathNode pn2, StagePathNode pn3, NodeEx node, Cc cc,
FlowState state, ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t,
Ap ap
) {
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow,
ApApprox innerArgApa, ApApprox apa
|
fwdFlowThroughStep1(pn1, pn2, pn3, call, cc, state, ccc, summaryCtx, argT, argAp, t,
ap, apa, ret, innerArgApa) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
private predicate step(
StagePathNode pn1, NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx,
TypOption argT, ApOption argAp, Typ t, Ap ap
) {
exists(NodeEx mid, FlowState state0, Typ t0, LocalCc localCc |
pn1 = TStagePathNodeMid(mid, state0, cc, summaryCtx, argT, argAp, t0, ap) and
localCc = getLocalCc(cc)
|
localStep(mid, state0, node, state, true, _, localCc) and
t = t0
or
localStep(mid, state0, node, state, false, t, localCc) and
ap instanceof ApNil
)
or
exists(NodeEx mid, FlowState state0, Typ t0 |
pn1 = TStagePathNodeMid(mid, state0, _, _, _, _, t0, ap) and
cc = ccNone() and
summaryCtx = TParamNodeNone() and
argT instanceof TypOption::None and
argAp = apNone()
|
jumpStepEx(mid, node) and
state = state0 and
t = t0
or
additionalJumpStep(mid, node, _) and
state = state0 and
t = getNodeTyp(node) and
ap instanceof ApNil
or
additionalJumpStateStep(mid, state0, node, state) and
t = getNodeTyp(node) and
ap instanceof ApNil
)
or
// store
exists(NodeEx mid, Content c, Typ t0, Ap ap0 |
pn1 = TStagePathNodeMid(mid, state, cc, summaryCtx, argT, argAp, t0, ap0) and
fwdFlowStore(mid, t0, ap0, c, t, node, state, cc, summaryCtx, argT, argAp) and
ap = apCons(c, t0, ap0)
)
or
// read
exists(NodeEx mid, Typ t0, Ap ap0, Content c |
pn1 = TStagePathNodeMid(mid, state, cc, summaryCtx, argT, argAp, t0, ap0) and
fwdFlowRead(t0, ap0, c, mid, node, state, cc, summaryCtx, argT, argAp) and
fwdFlowConsCand(t0, ap0, c, t, ap)
)
or
// flow into a callable
exists(
ArgNodeEx arg, boolean allowsFlowThrough, Cc outercc, ParamNodeOption outerSummaryCtx,
TypOption outerArgT, ApOption outerArgAp
|
pn1 =
TStagePathNodeMid(arg, state, outercc, outerSummaryCtx, outerArgT, outerArgAp, t, ap) and
fwdFlowInStep(arg, node, state, outercc, cc, outerSummaryCtx, outerArgT, outerArgAp,
t, ap, allowsFlowThrough) and
if allowsFlowThrough = true
then (
summaryCtx = TParamNodeSome(node.asNode()) and
argT = TypOption::some(t) and
argAp = apSome(ap)
) else (
summaryCtx = TParamNodeNone() and
argT instanceof TypOption::None and
argAp = apNone()
)
)
or
// flow out of a callable
exists(RetNodeEx ret, CcNoCall innercc, boolean allowsFieldFlow, ApApprox apa |
pn1 = TStagePathNodeMid(ret, state, innercc, summaryCtx, argT, argAp, t, ap) and
fwdFlowIntoRet(ret, state, innercc, summaryCtx, argT, argAp, t, ap, apa) and
fwdFlowOutValidEdge(_, ret, innercc, _, node, cc, apa, allowsFieldFlow) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
or
// flow through a callable
fwdFlowThroughStep2(pn1, _, _, node, cc, state, summaryCtx, argT, argAp, t, ap)
}
query predicate subpaths(
StagePathNode arg, StagePathNode par, StagePathNode ret, StagePathNode out
) {
exists(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t0, Typ t, Ap ap
|
fwdFlowThroughStep2(arg, par, ret, node, cc, state, summaryCtx, argT, argAp, t0, ap) and
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, t0, t, ap, _) and
out = TStagePathNodeMid(node, state, cc, summaryCtx, argT, argAp, t, ap)
)
}
query predicate edges(StagePathNode pn1, StagePathNode pn2) {
exists(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t0, Typ t, Ap ap
|
step(pn1, node, state, cc, summaryCtx, argT, argAp, t0, ap) and
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, t0, t, ap, _) and
pn2 = TStagePathNodeMid(node, state, cc, summaryCtx, argT, argAp, t, ap)
)
or
pn1.isArbitrarySource() and pn2.isSource()
or
pn1.isSink() and pn2.isArbitrarySink()
}
}
additional predicate stats(
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, int calledges,
int tfnodes, int tftuples
@@ -2853,12 +3153,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
private import LocalFlowBigStep
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
private predicate castingNodeEx(NodeEx node) {
node.asNode() instanceof CastingNode or exists(node.asParamReturnNode())
}
private module Stage3Param implements MkStage<Stage2>::StageParam {
private module PrevStage = Stage2;
class Typ = DataFlowType;
class Typ = Unit;
class Ap = ApproxAccessPathFront;
@@ -2866,7 +3168,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
Typ getTyp(DataFlowType t) { result = t }
Typ getTyp(DataFlowType t) { any() }
bindingset[c, t, tail]
Ap apCons(Content c, Typ t, Ap tail) { result.getAHead() = c and exists(t) and exists(tail) }
@@ -2903,7 +3205,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
Typ t, LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _, _) and
localFlowBigStep(node1, state1, node2, state2, preservesValue, _, _, _) and
exists(t) and
exists(lcc)
}
@@ -2926,7 +3229,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
// the cons candidates including types are used to construct subsequent
// access path approximations.
t0 = t and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
(
notExpectsContent(node)
or
@@ -2935,11 +3237,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
}
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, 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(typ, contentType)
}
predicate typecheckStore(Typ typ, DataFlowType contentType) { any() }
}
private module Stage3 = MkStage<Stage2>::Stage<Stage3Param>;
@@ -2949,7 +3247,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
if castingNodeEx(node)
then
exists(DataFlowType nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
if typeStrongerThanFilter(nt, t0)
then t = nt
else (
compatibleTypesFilter(nt, t0) and t = t0
)
)
else t = t0
}
@@ -3048,7 +3350,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
predicate typecheckStore(Typ typ, 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(typ, contentType)
compatibleTypesFilter(typ, contentType)
}
}
@@ -3304,7 +3606,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType) {
compatibleTypes(typ, contentType)
compatibleTypesFilter(typ, contentType)
}
}
@@ -4244,7 +4546,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
Stage5::storeStepCand(mid.getNodeExOutgoing(), _, c, node, contentType, t) and
state = mid.getState() and
cc = mid.getCallContext() and
compatibleTypes(t0, contentType)
compatibleTypesFilter(t0, contentType)
)
}
@@ -4639,67 +4941,127 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
*
* Calculates per-stage metrics for data flow.
*/
predicate stageStats(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stage = "1 Fwd" and
n = 10 and
Stage1::stats(true, nodes, fields, conscand, states, tuples, calledges) and
tfnodes = -1 and
tftuples = -1
or
stage = "1 Rev" and
n = 15 and
Stage1::stats(false, nodes, fields, conscand, states, tuples, calledges) and
tfnodes = -1 and
tftuples = -1
or
stage = "2 Fwd" and
n = 20 and
Stage2::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "2 Rev" and
n = 25 and
Stage2::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "3 Fwd" and
n = 30 and
Stage3::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "3 Rev" and
n = 35 and
Stage3::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "4 Fwd" and
n = 40 and
Stage4::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "4 Rev" and
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "6 Fwd" and
n = 60 and
finalStats(true, nodes, fields, conscand, states, tuples) and
calledges = -1 and
tfnodes = -1 and
tftuples = -1
or
stage = "6 Rev" and
n = 65 and
finalStats(false, nodes, fields, conscand, states, tuples) and
calledges = -1 and
tfnodes = -1 and
tftuples = -1
predicate stageStats = Debug::stageStats/10;
private module Stage2alias = Stage2;
private module Stage3alias = Stage3;
private module Stage4alias = Stage4;
private module Stage5alias = Stage5;
/**
* INTERNAL: Only for debugging.
*
* Contains references to individual pruning stages.
*/
module Debug {
module Stage2 = Stage2alias;
module Stage3 = Stage3alias;
module Stage4 = Stage4alias;
module Stage5 = Stage5alias;
predicate stageStats1(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stage = "1 Fwd" and
n = 10 and
Stage1::stats(true, nodes, fields, conscand, states, tuples, calledges) and
tfnodes = -1 and
tftuples = -1
or
stage = "1 Rev" and
n = 15 and
Stage1::stats(false, nodes, fields, conscand, states, tuples, calledges) and
tfnodes = -1 and
tftuples = -1
}
predicate stageStats2(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stageStats1(n, stage, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "2 Fwd" and
n = 20 and
Stage2::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "2 Rev" and
n = 25 and
Stage2::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
}
predicate stageStats3(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stageStats2(n, stage, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "3 Fwd" and
n = 30 and
Stage3::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "3 Rev" and
n = 35 and
Stage3::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
}
predicate stageStats4(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stageStats3(n, stage, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "4 Fwd" and
n = 40 and
Stage4::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "4 Rev" and
n = 45 and
Stage4::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
}
predicate stageStats5(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stageStats4(n, stage, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "5 Fwd" and
n = 50 and
Stage5::stats(true, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "5 Rev" and
n = 55 and
Stage5::stats(false, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
}
predicate stageStats(
int n, string stage, int nodes, int fields, int conscand, int states, int tuples,
int calledges, int tfnodes, int tftuples
) {
stageStats5(n, stage, nodes, fields, conscand, states, tuples, calledges, tfnodes, tftuples)
or
stage = "6 Fwd" and
n = 60 and
finalStats(true, nodes, fields, conscand, states, tuples) and
calledges = -1 and
tfnodes = -1 and
tftuples = -1
or
stage = "6 Rev" and
n = 65 and
finalStats(false, nodes, fields, conscand, states, tuples) and
calledges = -1 and
tfnodes = -1 and
tftuples = -1
}
}
private signature predicate flag();
@@ -5294,7 +5656,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
storeExUnrestricted(midNode, c, node, contentType, t2) and
ap2.getHead() = c and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(t1, contentType)
compatibleTypesFilter(t1, contentType)
)
}

View File

@@ -288,7 +288,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
not expectsContent(node, _) and
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeDataFlowType(node))
then compatibleTypesFilter(t, getNodeDataFlowType(node))
else any()
}
@@ -886,6 +886,20 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate compatibleTypesCached(DataFlowType t1, DataFlowType t2) { compatibleTypes(t1, t2) }
private predicate relevantType(DataFlowType t) { t = getNodeType(_) }
cached
predicate isTopType(DataFlowType t) {
strictcount(DataFlowType t0 | relevantType(t0)) =
strictcount(DataFlowType t0 | relevantType(t0) and compatibleTypesCached(t, t0))
}
cached
predicate typeStrongerThanCached(DataFlowType t1, DataFlowType t2) { typeStrongerThan(t1, t2) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
@@ -1118,7 +1132,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
exists(ParameterPosition ppos |
viableParam(call, ppos, p) and
argumentPositionMatch(call, arg, ppos) and
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
compatibleTypesFilter(getNodeDataFlowType(arg), getNodeDataFlowType(p)) and
golangSpecificParamArgFilter(call, p, arg)
)
}
@@ -1271,10 +1285,10 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
then
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
compatibleTypesFilter(getNodeDataFlowType(p), getNodeDataFlowType(node))
or
// getter
compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
compatibleTypesFilter(read.getContentType(), getNodeDataFlowType(node))
else any()
}
@@ -1307,7 +1321,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
compatibleTypesFilter(getNodeDataFlowType(p), read.getContainerType())
)
or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read, model)
@@ -1368,11 +1382,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
compatibleTypesFilter(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or
// getter
compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
compatibleTypesFilter(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypesFilter(read.getContentType(), getNodeDataFlowType(out))
)
}
@@ -1622,7 +1636,15 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
bindingset[t1, t2]
pragma[inline_late]
private predicate typeStrongerThan0(DataFlowType t1, DataFlowType t2) { typeStrongerThan(t1, t2) }
predicate compatibleTypesFilter(DataFlowType t1, DataFlowType t2) {
compatibleTypesCached(t1, t2)
}
bindingset[t1, t2]
pragma[inline_late]
predicate typeStrongerThanFilter(DataFlowType t1, DataFlowType t2) {
typeStrongerThanCached(t1, t2)
}
private predicate callEdge(DataFlowCall call, DataFlowCallable c, ArgNode arg, ParamNode p) {
viableParamArg(call, p, arg) and
@@ -1703,7 +1725,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
nodeDataFlowType(arg, at) and
nodeDataFlowType(p, pt) and
relevantCallEdge(_, _, arg, p) and
typeStrongerThan0(pt, at)
typeStrongerThanFilter(pt, at)
)
or
exists(ParamNode p, DataFlowType at, DataFlowType pt |
@@ -1714,7 +1736,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
nodeDataFlowType(p, pt) and
paramMustFlow(p, arg) and
relevantCallEdge(_, _, arg, _) and
typeStrongerThan0(at, pt)
typeStrongerThanFilter(at, pt)
)
or
exists(ParamNode p |
@@ -1754,7 +1776,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
nodeDataFlowType(arg, at) and
nodeDataFlowType(p, pt) and
relevantCallEdge(_, _, arg, p) and
typeStrongerThan0(at, pt)
typeStrongerThanFilter(at, pt)
)
or
exists(ArgNode arg |
@@ -1823,8 +1845,13 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
* stronger then compatibility is checked and `t1` is returned.
*/
bindingset[t1, t2]
pragma[inline_late]
DataFlowType getStrongestType(DataFlowType t1, DataFlowType t2) {
if typeStrongerThan(t2, t1) then result = t2 else (compatibleTypes(t1, t2) and result = t1)
if typeStrongerThanCached(t2, t1)
then result = t2
else (
compatibleTypesFilter(t1, t2) and result = t1
)
}
/**
@@ -1945,7 +1972,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
exists(DataFlowType t1, DataFlowType t2 |
typeFlowArgType(arg, t1, cc) and
relevantArgParamIn(arg, p, t2) and
compatibleTypes(t1, t2)
compatibleTypesFilter(t1, t2)
)
}
@@ -1989,7 +2016,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
exists(DataFlowType t1, DataFlowType t2 |
typeFlowParamType(p, t1, false) and
relevantArgParamOut(arg, p, t2) and
compatibleTypes(t1, t2)
compatibleTypesFilter(t1, t2)
)
}

View File

@@ -4,7 +4,6 @@
private import codeql.dataflow.DataFlow as DF
private import codeql.util.Location
private import DataFlowImpl
private import AccessPathSyntax as AccessPathSyntax
/**
@@ -271,6 +270,20 @@ module Make<
NeutralSummaryCallable() { this.getKind() = "summary" }
}
/**
* A callable that has a neutral source model.
*/
class NeutralSourceCallable extends NeutralCallableFinal {
NeutralSourceCallable() { this.getKind() = "source" }
}
/**
* A callable that has a neutral sink model.
*/
class NeutralSinkCallable extends NeutralCallableFinal {
NeutralSinkCallable() { this.getKind() = "sink" }
}
/**
* A callable that has a neutral model.
*/
@@ -1740,6 +1753,37 @@ module Make<
)
}
final private class SourceOrSinkElementFinal = SourceOrSinkElement;
bindingset[this]
abstract private class SourceSinkModelCallableBase extends SourceOrSinkElementFinal {
/**
* Holds if there exists a manual model that applies to this.
*/
final predicate hasManualModel() { any(Provenance p | this.hasProvenance(p)).isManual() }
/**
* Holds if this has provenance `p`.
*/
abstract predicate hasProvenance(Provenance p);
}
/**
* A callable that has a source model.
*/
abstract class SourceModelCallable extends SourceSinkModelCallableBase {
bindingset[this]
SourceModelCallable() { exists(this) }
}
/**
* A callable that has a sink model.
*/
abstract class SinkModelCallable extends SourceSinkModelCallableBase {
bindingset[this]
SinkModelCallable() { exists(this) }
}
/** A source or sink relevant for testing. */
signature class RelevantSourceOrSinkElementSig extends SourceOrSinkElement {
/** Gets the string representation of this callable used by `source/1` or `sink/1`. */

View File

@@ -5,6 +5,8 @@
* In addition to the `PathGraph`, a `query predicate models` is provided to
* list the contents of the referenced MaD rows.
*/
module;
signature predicate interpretModelForTestSig(QlBuiltins::ExtensionId madId, string model);
signature class PathNodeSig {