mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Merge branch 'main' into js/shared-dataflow-merge-main
This commit is contained in:
@@ -1,3 +1,15 @@
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/dataflow/change-notes/released/1.0.2.md
Normal file
3
shared/dataflow/change-notes/released/1.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.2
|
||||
|
||||
No user-facing changes.
|
||||
3
shared/dataflow/change-notes/released/1.0.3.md
Normal file
3
shared/dataflow/change-notes/released/1.0.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
3
shared/dataflow/change-notes/released/1.0.4.md
Normal file
3
shared/dataflow/change-notes/released/1.0.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.1
|
||||
lastReleaseVersion: 1.0.4
|
||||
|
||||
@@ -76,9 +76,6 @@ signature module InputSig<LocationSig Location> {
|
||||
Location getLocation();
|
||||
|
||||
DataFlowCallable getEnclosingCallable();
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder();
|
||||
}
|
||||
|
||||
class DataFlowCallable {
|
||||
@@ -87,9 +84,6 @@ signature module InputSig<LocationSig Location> {
|
||||
|
||||
/** Gets the location of this callable. */
|
||||
Location getLocation();
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder();
|
||||
}
|
||||
|
||||
class ReturnKind {
|
||||
@@ -130,8 +124,6 @@ signature module InputSig<LocationSig Location> {
|
||||
string toString();
|
||||
}
|
||||
|
||||
string ppReprType(DataFlowType t);
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible types.
|
||||
*
|
||||
@@ -266,8 +258,6 @@ signature module InputSig<LocationSig Location> {
|
||||
class NodeRegion {
|
||||
/** Holds if this region contains `n`. */
|
||||
predicate contains(Node n);
|
||||
|
||||
int totalOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,12 @@ signature module InputSig<LocationSig Location> {
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString();
|
||||
|
||||
/** Gets the `i`th node in this basic block. */
|
||||
ControlFlowNode getNode(int i);
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length();
|
||||
|
||||
/** Gets the enclosing callable. */
|
||||
Callable getEnclosingCallable();
|
||||
|
||||
@@ -24,6 +30,15 @@ signature module InputSig<LocationSig Location> {
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/** A control flow node. */
|
||||
class ControlFlowNode {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates basic block `bb`, if any.
|
||||
*
|
||||
@@ -672,6 +687,8 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
private module CaptureSsaInput implements Ssa::InputSig<Location> {
|
||||
final class BasicBlock = Input::BasicBlock;
|
||||
|
||||
final class ControlFlowNode = Input::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = Input::getImmediateBasicBlockDominator(bb)
|
||||
}
|
||||
@@ -717,10 +734,10 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
TSynthPhi(CaptureSsa::DefinitionExt phi) {
|
||||
phi instanceof CaptureSsa::PhiNode or phi instanceof CaptureSsa::PhiReadNode
|
||||
} or
|
||||
TExprNode(Expr expr, boolean isPost) {
|
||||
expr instanceof VariableRead and isPost = [false, true]
|
||||
TExprNode(Expr expr, Boolean isPost) {
|
||||
expr instanceof VariableRead
|
||||
or
|
||||
synthRead(_, _, _, _, expr) and isPost = [false, true]
|
||||
synthRead(_, _, _, _, expr)
|
||||
} or
|
||||
TParamNode(CapturedParameter p) or
|
||||
TThisParamNode(Callable c) { captureAccess(_, c) } or
|
||||
|
||||
@@ -1809,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)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1837,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
|
||||
@@ -1940,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]
|
||||
@@ -2026,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)
|
||||
}
|
||||
|
||||
@@ -2042,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 {
|
||||
@@ -2058,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]
|
||||
@@ -2085,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]
|
||||
@@ -2520,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
|
||||
@@ -3178,9 +3445,11 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
AccessPathApproxConsNil() { this = TConsNil(c, t) }
|
||||
|
||||
private string ppTyp() { result = t.toString() and result != "" }
|
||||
|
||||
override string toString() {
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = "[" + c.toString() + "]" + concat(" : " + ppReprType(t))
|
||||
// The `concat` becomes "" if `ppTyp` has no result.
|
||||
result = "[" + c.toString() + "]" + concat(" : " + this.ppTyp())
|
||||
}
|
||||
|
||||
override Content getHead() { result = c }
|
||||
@@ -3401,7 +3670,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
override string toString() { result = p + concat(" : " + ppReprType(t)) + " " + ap }
|
||||
private string ppTyp() { result = t.toString() and result != "" }
|
||||
|
||||
override string toString() { result = p + concat(" : " + this.ppTyp()) + " " + ap }
|
||||
|
||||
Location getLocation() { result = p.getLocation() }
|
||||
}
|
||||
@@ -3668,10 +3939,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
|
||||
override int length() { result = 1 + tail_.length() }
|
||||
|
||||
private string ppTyp() { result = t.toString() and result != "" }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
tail_ = TAccessPathNil() and
|
||||
needsSuffix = false and
|
||||
result = head_.toString() + "]" + concat(" : " + ppReprType(t))
|
||||
result = head_.toString() + "]" + concat(" : " + this.ppTyp())
|
||||
or
|
||||
result = head_ + ", " + tail_.(AccessPathCons).toStringImpl(needsSuffix)
|
||||
or
|
||||
@@ -3820,9 +4093,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private string ppType() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
exists(DataFlowType t | t = this.(PathNodeMid).getType() |
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
exists(string t | t = this.(PathNodeMid).getType().toString() |
|
||||
if t = "" then result = "" else result = " : " + t
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4254,7 +4526,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
pathThroughCallable(mid, node, state, cc, t, ap, label) and
|
||||
sc = mid.getSummaryCtx() and
|
||||
isStoreStep = false and
|
||||
summaryLabel = mid.getSummaryLabel()
|
||||
summaryLabel = mergeLabels(mid.getSummaryLabel(), label)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -4674,67 +4946,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();
|
||||
@@ -5075,9 +5407,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
|
||||
private string ppType() {
|
||||
this instanceof PartialPathNodeRev and result = ""
|
||||
or
|
||||
exists(DataFlowType t | t = this.(PartialPathNodeFwd).getType() |
|
||||
// The `concat` becomes "" if `ppReprType` has no result.
|
||||
result = concat(" : " + ppReprType(t))
|
||||
exists(string t | t = this.(PartialPathNodeFwd).getType().toString() |
|
||||
if t = "" then result = "" else result = " : " + t
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ private import codeql.util.Location
|
||||
private import codeql.util.Option
|
||||
private import codeql.util.Unit
|
||||
private import codeql.util.Option
|
||||
private import codeql.util.internal.MakeSets
|
||||
|
||||
module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
private import Lang
|
||||
@@ -502,24 +501,21 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
)
|
||||
}
|
||||
|
||||
private module CallSetsInput implements MkSetsInputSig {
|
||||
class Key = TCallEdge;
|
||||
|
||||
class Value = DataFlowCall;
|
||||
|
||||
DataFlowCall getAValue(TCallEdge ctxEdge) {
|
||||
exists(DataFlowCall ctx, DataFlowCallable c |
|
||||
ctxEdge = TMkCallEdge(ctx, c) and
|
||||
reducedViableImplInCallContext(result, c, ctx)
|
||||
)
|
||||
}
|
||||
|
||||
int totalorder(DataFlowCall e) { result = callOrder(e) }
|
||||
private DataFlowCall getACallWithReducedViableImpl(TCallEdge ctxEdge) {
|
||||
exists(DataFlowCall ctx, DataFlowCallable c |
|
||||
ctxEdge = TMkCallEdge(ctx, c) and
|
||||
reducedViableImplInCallContext(result, c, ctx)
|
||||
)
|
||||
}
|
||||
|
||||
private module CallSets = MakeSets<CallSetsInput>;
|
||||
private module CallSets =
|
||||
QlBuiltins::InternSets<TCallEdge, DataFlowCall, getACallWithReducedViableImpl/1>;
|
||||
|
||||
private module CallSetOption = Option<CallSets::ValueSet>;
|
||||
private class CallSet0 extends CallSets::Set {
|
||||
string toString() { result = "CallSet" }
|
||||
}
|
||||
|
||||
private module CallSetOption = Option<CallSet0>;
|
||||
|
||||
/**
|
||||
* A set of call sites for which dispatch is affected by the call context.
|
||||
@@ -528,26 +524,23 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
*/
|
||||
private class CallSet = CallSetOption::Option;
|
||||
|
||||
private module DispatchSetsInput implements MkSetsInputSig {
|
||||
class Key = TCallEdge;
|
||||
|
||||
class Value = TCallEdge;
|
||||
|
||||
TCallEdge getAValue(TCallEdge ctxEdge) {
|
||||
exists(DataFlowCall ctx, DataFlowCallable c, DataFlowCall call, DataFlowCallable tgt |
|
||||
ctxEdge = mkCallEdge(ctx, c) and
|
||||
result = mkCallEdge(call, tgt) and
|
||||
viableImplInCallContextExtIn(call, ctx) = tgt and
|
||||
reducedViableImplInCallContext(call, c, ctx)
|
||||
)
|
||||
}
|
||||
|
||||
int totalorder(TCallEdge e) { result = edgeOrder(e) }
|
||||
private TCallEdge getAReducedViableEdge(TCallEdge ctxEdge) {
|
||||
exists(DataFlowCall ctx, DataFlowCallable c, DataFlowCall call, DataFlowCallable tgt |
|
||||
ctxEdge = mkCallEdge(ctx, c) and
|
||||
result = mkCallEdge(call, tgt) and
|
||||
viableImplInCallContextExtIn(call, ctx) = tgt and
|
||||
reducedViableImplInCallContext(call, c, ctx)
|
||||
)
|
||||
}
|
||||
|
||||
private module DispatchSets = MakeSets<DispatchSetsInput>;
|
||||
private module DispatchSets =
|
||||
QlBuiltins::InternSets<TCallEdge, TCallEdge, getAReducedViableEdge/1>;
|
||||
|
||||
private module DispatchSetsOption = Option<DispatchSets::ValueSet>;
|
||||
private class DispatchSet0 extends DispatchSets::Set {
|
||||
string toString() { result = "DispatchSet" }
|
||||
}
|
||||
|
||||
private module DispatchSetsOption = Option<DispatchSet0>;
|
||||
|
||||
/**
|
||||
* A set of call edges that are allowed in the call context. This applies to
|
||||
@@ -561,7 +554,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
private class DispatchSet = DispatchSetsOption::Option;
|
||||
|
||||
private predicate relevantCtx(TCallEdge ctx) {
|
||||
exists(CallSets::getValueSet(ctx)) or exists(getUnreachableSet(ctx))
|
||||
exists(CallSets::getSet(ctx)) or exists(getUnreachableSet(ctx))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -570,14 +563,14 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
) {
|
||||
relevantCtx(ctx) and
|
||||
(
|
||||
CallSets::getValueSet(ctx) = calls.asSome()
|
||||
CallSets::getSet(ctx) = calls.asSome()
|
||||
or
|
||||
not exists(CallSets::getValueSet(ctx)) and calls.isNone()
|
||||
not exists(CallSets::getSet(ctx)) and calls.isNone()
|
||||
) and
|
||||
(
|
||||
DispatchSets::getValueSet(ctx) = tgts.asSome()
|
||||
DispatchSets::getSet(ctx) = tgts.asSome()
|
||||
or
|
||||
not exists(DispatchSets::getValueSet(ctx)) and tgts.isNone()
|
||||
not exists(DispatchSets::getSet(ctx)) and tgts.isNone()
|
||||
) and
|
||||
(
|
||||
getUnreachableSet(ctx) = unreachable.asSome()
|
||||
@@ -1515,40 +1508,20 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
newtype TCallEdge =
|
||||
TMkCallEdge(DataFlowCall call, DataFlowCallable tgt) { viableCallableExt(call) = tgt }
|
||||
|
||||
cached
|
||||
int edgeOrder(TCallEdge edge) {
|
||||
edge =
|
||||
rank[result](TCallEdge e, DataFlowCall call, DataFlowCallable tgt |
|
||||
e = TMkCallEdge(call, tgt)
|
||||
|
|
||||
e order by call.totalorder(), tgt.totalorder()
|
||||
)
|
||||
private NodeRegion getAnUnreachableRegion(TCallEdge edge) {
|
||||
exists(DataFlowCall call, DataFlowCallable tgt |
|
||||
edge = mkCallEdge(call, tgt) and
|
||||
getNodeRegionEnclosingCallable(result) = tgt and
|
||||
isUnreachableInCallCached(result, call)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
int callOrder(DataFlowCall call) { result = call.totalorder() }
|
||||
|
||||
private module UnreachableSetsInput implements MkSetsInputSig {
|
||||
class Key = TCallEdge;
|
||||
|
||||
class Value = NodeRegion;
|
||||
|
||||
NodeRegion getAValue(TCallEdge edge) {
|
||||
exists(DataFlowCall call, DataFlowCallable tgt |
|
||||
edge = mkCallEdge(call, tgt) and
|
||||
getNodeRegionEnclosingCallable(result) = tgt and
|
||||
isUnreachableInCallCached(result, call)
|
||||
)
|
||||
}
|
||||
|
||||
int totalorder(NodeRegion nr) { result = nr.totalOrder() }
|
||||
}
|
||||
|
||||
private module UnreachableSets = MakeSets<UnreachableSetsInput>;
|
||||
private module UnreachableSets =
|
||||
QlBuiltins::InternSets<TCallEdge, NodeRegion, getAnUnreachableRegion/1>;
|
||||
|
||||
/** A set of nodes that is unreachable in some call context. */
|
||||
cached
|
||||
class UnreachableSet instanceof UnreachableSets::ValueSet {
|
||||
class UnreachableSet instanceof UnreachableSets::Set {
|
||||
cached
|
||||
string toString() { result = "Unreachable" }
|
||||
|
||||
@@ -1562,7 +1535,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
}
|
||||
|
||||
cached
|
||||
UnreachableSet getUnreachableSet(TCallEdge edge) { result = UnreachableSets::getValueSet(edge) }
|
||||
UnreachableSet getUnreachableSet(TCallEdge edge) { result = UnreachableSets::getSet(edge) }
|
||||
|
||||
private module UnreachableSetOption = Option<UnreachableSet>;
|
||||
|
||||
@@ -1579,7 +1552,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(UnreachableSets::ValueSet ns)
|
||||
TSpecificLocalCall(UnreachableSets::Set ns)
|
||||
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
|
||||
@@ -9,6 +9,8 @@ module;
|
||||
|
||||
signature predicate interpretModelForTestSig(QlBuiltins::ExtensionId madId, string model);
|
||||
|
||||
signature predicate queryResultsSig(string relation, int row, int column, string data);
|
||||
|
||||
signature class PathNodeSig {
|
||||
string toString();
|
||||
}
|
||||
@@ -28,14 +30,14 @@ signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/** Transforms a `PathGraph` by printing the provenance information. */
|
||||
module ShowProvenance<
|
||||
interpretModelForTestSig/2 interpretModelForTest, PathNodeSig PathNode,
|
||||
PathGraphSig<PathNode> PathGraph>
|
||||
private signature predicate provenanceSig(string model);
|
||||
|
||||
private module TranslateModels<
|
||||
interpretModelForTestSig/2 interpretModelForTest, provenanceSig/1 provenance>
|
||||
{
|
||||
private predicate madIds(string madId) {
|
||||
exists(string model |
|
||||
PathGraph::edges(_, _, _, model) and
|
||||
provenance(model) and
|
||||
model.regexpFind("(?<=MaD:)[0-9]*", _, _) = madId
|
||||
)
|
||||
}
|
||||
@@ -44,14 +46,15 @@ module ShowProvenance<
|
||||
madId = rank[r](string madId0 | madIds(madId0) | madId0 order by madId0.toInt())
|
||||
}
|
||||
|
||||
query predicate models(int r, string model) {
|
||||
/** Lists the renumbered and pretty-printed models used in the edges relation. */
|
||||
predicate models(int r, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
rankedMadIds(madId.toString(), r) and interpretModelForTest(madId, model)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate translateModelsPart(string model1, string model2, int i) {
|
||||
PathGraph::edges(_, _, _, model1) and
|
||||
provenance(model1) and
|
||||
exists(string s | model1.splitAt("MaD:", i) = s |
|
||||
model2 = s and i = 0
|
||||
or
|
||||
@@ -65,17 +68,29 @@ module ShowProvenance<
|
||||
)
|
||||
}
|
||||
|
||||
private predicate translateModels(string model1, string model2) {
|
||||
predicate translateModels(string model1, string model2) {
|
||||
exists(int i |
|
||||
translateModelsPart(model1, model2, i) and
|
||||
not translateModelsPart(model1, _, i + 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Transforms a `PathGraph` by printing the provenance information. */
|
||||
module ShowProvenance<
|
||||
interpretModelForTestSig/2 interpretModelForTest, PathNodeSig PathNode,
|
||||
PathGraphSig<PathNode> PathGraph>
|
||||
{
|
||||
private predicate provenance(string model) { PathGraph::edges(_, _, _, model) }
|
||||
|
||||
private module Models = TranslateModels<interpretModelForTest/2, provenance/1>;
|
||||
|
||||
query predicate models(int r, string model) { Models::models(r, model) }
|
||||
|
||||
query predicate edges(PathNode a, PathNode b, string key, string val) {
|
||||
exists(string model |
|
||||
PathGraph::edges(a, b, key, model) and
|
||||
translateModels(model, val)
|
||||
Models::translateModels(model, val)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,3 +98,46 @@ module ShowProvenance<
|
||||
|
||||
query predicate subpaths = PathGraph::subpaths/4;
|
||||
}
|
||||
|
||||
/** Transforms a `PathGraph` by printing the provenance information. */
|
||||
module TranslateProvenanceResults<
|
||||
interpretModelForTestSig/2 interpretModelForTest, queryResultsSig/4 queryResults>
|
||||
{
|
||||
private int provenanceColumn() { result = 5 }
|
||||
|
||||
private predicate provenance(string model) { queryResults("edges", _, provenanceColumn(), model) }
|
||||
|
||||
private module Models = TranslateModels<interpretModelForTest/2, provenance/1>;
|
||||
|
||||
private newtype TModelRow = TMkModelRow(int r, string model) { Models::models(r, model) }
|
||||
|
||||
private predicate rankedModels(int i, int r, string model) {
|
||||
TMkModelRow(r, model) =
|
||||
rank[i](TModelRow row, int r0, string model0 |
|
||||
row = TMkModelRow(r0, model0)
|
||||
|
|
||||
row order by r0, model0
|
||||
)
|
||||
}
|
||||
|
||||
predicate results(string relation, int row, int column, string data) {
|
||||
queryResults(relation, row, column, data) and
|
||||
(relation != "edges" or column != provenanceColumn())
|
||||
or
|
||||
exists(string model |
|
||||
relation = "edges" and
|
||||
column = provenanceColumn() and
|
||||
queryResults(relation, row, column, model) and
|
||||
Models::translateModels(model, data)
|
||||
)
|
||||
or
|
||||
exists(int r, string model |
|
||||
relation = "models" and
|
||||
rankedModels(row, r, model)
|
||||
|
|
||||
column = 0 and data = r.toString()
|
||||
or
|
||||
column = 1 and data = model
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/dataflow
|
||||
version: 1.0.2-dev
|
||||
version: 1.0.5-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user