mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Merge remote-tracking branch 'upstream/main' into 'rc/3.14'
This commit is contained in:
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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`. */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user