Merge branch 'main' into js/shared-dataflow-merge-main

This commit is contained in:
Asger F
2024-08-02 13:18:38 +02:00
1505 changed files with 135513 additions and 35699 deletions

View File

@@ -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.

View File

@@ -0,0 +1,3 @@
## 1.0.2
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.1
lastReleaseVersion: 1.0.4

View File

@@ -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();
}
/**

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -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 =

View File

@@ -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
)
}
}

View File

@@ -1,5 +1,5 @@
name: codeql/dataflow
version: 1.0.2-dev
version: 1.0.5-dev
groups: shared
library: true
dependencies: